Merge remote-tracking branch 'remotes/origin/DLAB-2067' into new-datalab-name
diff --git a/build.properties b/build.properties
index 989bad1..275dfaa 100644
--- a/build.properties
+++ b/build.properties
@@ -16,4 +16,4 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-dlab.version=2.4
\ No newline at end of file
+datalab.version=2.4
\ No newline at end of file
diff --git a/integration-tests-cucumber/pom.xml b/integration-tests-cucumber/pom.xml
index d862bcb..4d00132 100644
--- a/integration-tests-cucumber/pom.xml
+++ b/integration-tests-cucumber/pom.xml
@@ -23,7 +23,7 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
-    <groupId>com.epam.dlab</groupId>
+    <groupId>com.epam.datalab</groupId>
     <artifactId>integration-tests</artifactId>
     <version>1.0.0-SNAPSHOT</version>
     <packaging>jar</packaging>
diff --git a/integration-tests-cucumber/src/main/java/org/apache/datalab/dto/EndpointDTO.java b/integration-tests-cucumber/src/main/java/org/apache/datalab/dto/EndpointDTO.java
new file mode 100644
index 0000000..cddbbe0
--- /dev/null
+++ b/integration-tests-cucumber/src/main/java/org/apache/datalab/dto/EndpointDTO.java
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.datalab.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+@AllArgsConstructor
+@NoArgsConstructor
+public class EndpointDTO {
+	private String name;
+	private String url;
+	private String account;
+	@JsonProperty("endpoint_tag")
+	private String tag;
+}
diff --git a/integration-tests-cucumber/src/main/java/org/apache/datalab/mongo/MongoDBHelper.java b/integration-tests-cucumber/src/main/java/org/apache/datalab/mongo/MongoDBHelper.java
new file mode 100644
index 0000000..fd2eb97
--- /dev/null
+++ b/integration-tests-cucumber/src/main/java/org/apache/datalab/mongo/MongoDBHelper.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 org.apache.datalab.mongo;
+
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
+import org.apache.datalab.util.PropertyHelper;
+
+public class MongoDBHelper {
+	private static final MongoClient client = MongoClients
+			.create(PropertyHelper.read("mongo.connection.string"));
+
+	public static void cleanCollection(String collection) {
+		client.getDatabase(PropertyHelper.read("mongo.db.name")).getCollection(collection).drop();
+	}
+}
diff --git a/integration-tests-cucumber/src/main/java/org/apache/datalab/util/JacksonMapper.java b/integration-tests-cucumber/src/main/java/org/apache/datalab/util/JacksonMapper.java
new file mode 100644
index 0000000..b2d9498
--- /dev/null
+++ b/integration-tests-cucumber/src/main/java/org/apache/datalab/util/JacksonMapper.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.datalab.util;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public final class JacksonMapper {
+	private static final ObjectMapper MAPPER = new ObjectMapper();
+
+	public static <T> String marshall(T obj) {
+		try {
+			return MAPPER.writeValueAsString(obj);
+		} catch (JsonProcessingException e) {
+			throw new IllegalArgumentException(e);
+		}
+	}
+}
diff --git a/integration-tests-cucumber/src/main/java/org/apache/datalab/util/PropertyHelper.java b/integration-tests-cucumber/src/main/java/org/apache/datalab/util/PropertyHelper.java
new file mode 100644
index 0000000..b42cd61
--- /dev/null
+++ b/integration-tests-cucumber/src/main/java/org/apache/datalab/util/PropertyHelper.java
@@ -0,0 +1,42 @@
+/*
+ * 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 org.apache.datalab.util;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Properties;
+
+public class PropertyHelper {
+
+	private final static Properties PROPERTIES;
+
+	static {
+		PROPERTIES = new Properties();
+		try (InputStream inputStream = new FileInputStream(System.getProperty("config.file"))) {
+			PROPERTIES.load(inputStream);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	public static String read(String prop) {
+		return PROPERTIES.getProperty(prop);
+	}
+}
diff --git a/integration-tests-cucumber/src/main/java/org/apache/dlab/dto/EndpointDTO.java b/integration-tests-cucumber/src/main/java/org/apache/dlab/dto/EndpointDTO.java
deleted file mode 100644
index 7cfdad2..0000000
--- a/integration-tests-cucumber/src/main/java/org/apache/dlab/dto/EndpointDTO.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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 org.apache.dlab.dto;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-@AllArgsConstructor
-@NoArgsConstructor
-public class EndpointDTO {
-	private String name;
-	private String url;
-	private String account;
-	@JsonProperty("endpoint_tag")
-	private String tag;
-}
diff --git a/integration-tests-cucumber/src/main/java/org/apache/dlab/mongo/MongoDBHelper.java b/integration-tests-cucumber/src/main/java/org/apache/dlab/mongo/MongoDBHelper.java
deleted file mode 100644
index 4903fd4..0000000
--- a/integration-tests-cucumber/src/main/java/org/apache/dlab/mongo/MongoDBHelper.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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 org.apache.dlab.mongo;
-
-import com.mongodb.client.MongoClient;
-import com.mongodb.client.MongoClients;
-import org.apache.dlab.util.PropertyHelper;
-
-public class MongoDBHelper {
-	private static final MongoClient client = MongoClients
-			.create(PropertyHelper.read("mongo.connection.string"));
-
-	public static void cleanCollection(String collection) {
-		client.getDatabase(PropertyHelper.read("mongo.db.name")).getCollection(collection).drop();
-	}
-}
diff --git a/integration-tests-cucumber/src/main/java/org/apache/dlab/util/JacksonMapper.java b/integration-tests-cucumber/src/main/java/org/apache/dlab/util/JacksonMapper.java
deleted file mode 100644
index ae4d5ce..0000000
--- a/integration-tests-cucumber/src/main/java/org/apache/dlab/util/JacksonMapper.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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 org.apache.dlab.util;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-public final class JacksonMapper {
-	private static final ObjectMapper MAPPER = new ObjectMapper();
-
-	public static <T> String marshall(T obj) {
-		try {
-			return MAPPER.writeValueAsString(obj);
-		} catch (JsonProcessingException e) {
-			throw new IllegalArgumentException(e);
-		}
-	}
-}
diff --git a/integration-tests-cucumber/src/main/java/org/apache/dlab/util/PropertyHelper.java b/integration-tests-cucumber/src/main/java/org/apache/dlab/util/PropertyHelper.java
deleted file mode 100644
index 71688e2..0000000
--- a/integration-tests-cucumber/src/main/java/org/apache/dlab/util/PropertyHelper.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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 org.apache.dlab.util;
-
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.Properties;
-
-public class PropertyHelper {
-
-	private final static Properties PROPERTIES;
-
-	static {
-		PROPERTIES = new Properties();
-		try (InputStream inputStream = new FileInputStream(System.getProperty("config.file"))) {
-			PROPERTIES.load(inputStream);
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-	}
-
-	public static String read(String prop) {
-		return PROPERTIES.getProperty(prop);
-	}
-}
diff --git a/integration-tests-cucumber/src/test/java/datalab/Constants.java b/integration-tests-cucumber/src/test/java/datalab/Constants.java
new file mode 100644
index 0000000..375d614
--- /dev/null
+++ b/integration-tests-cucumber/src/test/java/datalab/Constants.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 datalab;
+
+public interface Constants {
+    String API_URI = "https://localhost:8443/api/";
+}
diff --git a/integration-tests-cucumber/src/test/java/datalab/RunCucumberTest.java b/integration-tests-cucumber/src/test/java/datalab/RunCucumberTest.java
new file mode 100644
index 0000000..4fbc70c
--- /dev/null
+++ b/integration-tests-cucumber/src/test/java/datalab/RunCucumberTest.java
@@ -0,0 +1,29 @@
+/*
+ * 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 datalab;
+
+import cucumber.api.CucumberOptions;
+import cucumber.api.junit.Cucumber;
+import org.junit.runner.RunWith;
+
+@RunWith(Cucumber.class)
+@CucumberOptions(plugin = {"json:target/cucumber.json"})
+public class RunCucumberTest {
+}
diff --git a/integration-tests-cucumber/src/test/java/datalab/endpoint/EndpointSteps.java b/integration-tests-cucumber/src/test/java/datalab/endpoint/EndpointSteps.java
new file mode 100644
index 0000000..fa46141
--- /dev/null
+++ b/integration-tests-cucumber/src/test/java/datalab/endpoint/EndpointSteps.java
@@ -0,0 +1,116 @@
+/*
+ * 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 datalab.endpoint;
+
+import com.jayway.restassured.http.ContentType;
+import com.jayway.restassured.response.Response;
+import com.jayway.restassured.specification.RequestSpecification;
+import cucumber.api.java.en.And;
+import cucumber.api.java.en.Given;
+import cucumber.api.java.en.Then;
+import cucumber.api.java.en.When;
+import org.apache.datalab.dto.EndpointDTO;
+import org.apache.datalab.mongo.MongoDBHelper;
+import org.apache.datalab.util.JacksonMapper;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import static com.jayway.restassured.RestAssured.given;
+import static datalab.Constants.API_URI;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsEqual.equalTo;
+
+public class EndpointSteps {
+	private RequestSpecification request;
+	private Response response;
+	private String name;
+
+	@Given("User try to create new endpoint with name {string} and uri {string} and account {string} and {string}")
+	public void userTryToCreateNewEndpoint(String name, String uri, String account, String tag) {
+		this.name = name;
+		request = given().body(JacksonMapper.marshall(new EndpointDTO(name, uri, account, tag)))
+				.auth()
+				.oauth2("token123")
+				.contentType(ContentType.JSON);
+
+	}
+
+	@When("User send create new endpoint request")
+	public void userSendCreateNewEndpoint() {
+		response = request.post(API_URI + "endpoint");
+	}
+
+	@Given("There is no endpoints in DataLab")
+	public void thereIsNoEndpointsInDataLab() {
+		MongoDBHelper.cleanCollection("endpoints");
+
+	}
+
+	@Then("Response status code is {int}")
+	public void responseStatusCodeIs(int code) {
+		assertThat(response.getStatusCode(), equalTo(code));
+	}
+
+	@And("Endpoint URI is present in location header")
+	public void endpointURIIsPresentInLocationHeader() {
+		assertThat(response.getHeader("Location"), equalTo(API_URI + "endpoint/" + name));
+	}
+
+	@When("User try to get information about endpoint with name {string}")
+	public void userTryToGetInformationAboutEndpointWithName(String endpoint) throws URISyntaxException {
+		response = authenticatedRequest()
+				.get(new URI(API_URI + "endpoint/" + endpoint));
+
+	}
+
+	@And("Endpoint information is successfully returned with " +
+			"name {string}, uri {string}, account {string}, and tag {string}")
+	public void endpointInformationIsSuccessfullyReturnedWithNameUriAccountAndTag(String name, String uri,
+																				  String account, String tag) {
+		final EndpointDTO dto = response.getBody().as(EndpointDTO.class);
+		assertThat(dto.getAccount(), equalTo(account));
+		assertThat(dto.getName(), equalTo(name));
+		assertThat(dto.getUrl(), equalTo(uri));
+		assertThat(dto.getTag(), equalTo(tag));
+
+	}
+
+	@When("User try to get information about endpoints")
+	public void userTryToGetInformationAboutEndpoints() throws URISyntaxException {
+		response = authenticatedRequest()
+				.get(new URI(API_URI + "endpoint"));
+
+	}
+
+	@And("There are endpoints with name test1 and test2")
+	public void thereAreEndpointsWithNameTestAndTest() {
+		final EndpointDTO[] endpoints = response.getBody().as(EndpointDTO[].class);
+		assertThat(2, equalTo(endpoints.length));
+		assertThat("test1", equalTo(endpoints[0].getName()));
+		assertThat("test2", equalTo(endpoints[1].getName()));
+	}
+
+	private RequestSpecification authenticatedRequest() {
+		return given()
+				.auth()
+				.oauth2("token123");
+	}
+}
diff --git a/integration-tests-cucumber/src/test/java/datalab/login/LoginSteps.java b/integration-tests-cucumber/src/test/java/datalab/login/LoginSteps.java
new file mode 100644
index 0000000..9351b33
--- /dev/null
+++ b/integration-tests-cucumber/src/test/java/datalab/login/LoginSteps.java
@@ -0,0 +1,63 @@
+/*
+ * 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 datalab.login;
+
+import com.jayway.restassured.http.ContentType;
+import com.jayway.restassured.response.Response;
+import com.jayway.restassured.specification.RequestSpecification;
+import cucumber.api.java.en.Given;
+import cucumber.api.java.en.Then;
+import cucumber.api.java.en.When;
+import gherkin.deps.com.google.gson.JsonObject;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import static com.jayway.restassured.RestAssured.given;
+import static datalab.Constants.API_URI;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class LoginSteps {
+
+
+    private static final String LOGIN_RESOURCE_PATH = API_URI + "user/login";
+    private RequestSpecification request;
+    private Response response;
+
+    @Given("User try to login to Datalab with {string} and {string}")
+    public void userProvidedLoginAndPassword(String username, String password) {
+        JsonObject jsonObject = new JsonObject();
+        jsonObject.addProperty("username", username);
+        jsonObject.addProperty("password", password);
+        request = given().body(jsonObject.toString()).contentType(ContentType.JSON);
+    }
+
+    @When("user try to login")
+    public void userTryToLogin() throws URISyntaxException {
+        response = request.post(new URI(LOGIN_RESOURCE_PATH));
+    }
+
+    @Then("response code is {string}")
+    public void responseCodeIs(String status) {
+        assertThat(response.getStatusCode(), equalTo(Integer.valueOf(status)));
+
+    }
+}
diff --git a/integration-tests-cucumber/src/test/java/dlab/Constants.java b/integration-tests-cucumber/src/test/java/dlab/Constants.java
deleted file mode 100644
index 8e1b6b9..0000000
--- a/integration-tests-cucumber/src/test/java/dlab/Constants.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 dlab;
-
-public interface Constants {
-	String API_URI = "https://localhost:8443/api/";
-}
diff --git a/integration-tests-cucumber/src/test/java/dlab/RunCucumberTest.java b/integration-tests-cucumber/src/test/java/dlab/RunCucumberTest.java
deleted file mode 100644
index fb03b55..0000000
--- a/integration-tests-cucumber/src/test/java/dlab/RunCucumberTest.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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 dlab;
-
-import cucumber.api.CucumberOptions;
-import cucumber.api.junit.Cucumber;
-import org.junit.runner.RunWith;
-
-@RunWith(Cucumber.class)
-@CucumberOptions(plugin = {"json:target/cucumber.json"})
-public class RunCucumberTest {
-}
diff --git a/integration-tests-cucumber/src/test/java/dlab/endpoint/EndpointSteps.java b/integration-tests-cucumber/src/test/java/dlab/endpoint/EndpointSteps.java
deleted file mode 100644
index 1c1d43a..0000000
--- a/integration-tests-cucumber/src/test/java/dlab/endpoint/EndpointSteps.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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 dlab.endpoint;
-
-import com.jayway.restassured.http.ContentType;
-import com.jayway.restassured.response.Response;
-import com.jayway.restassured.specification.RequestSpecification;
-import cucumber.api.java.en.And;
-import cucumber.api.java.en.Given;
-import cucumber.api.java.en.Then;
-import cucumber.api.java.en.When;
-import org.apache.dlab.dto.EndpointDTO;
-import org.apache.dlab.mongo.MongoDBHelper;
-import org.apache.dlab.util.JacksonMapper;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import static com.jayway.restassured.RestAssured.given;
-import static dlab.Constants.API_URI;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.IsEqual.equalTo;
-
-public class EndpointSteps {
-	private RequestSpecification request;
-	private Response response;
-	private String name;
-
-	@Given("User try to create new endpoint with name {string} and uri {string} and account {string} and {string}")
-	public void userTryToCreateNewEndpoint(String name, String uri, String account, String tag) {
-		this.name = name;
-		request = given().body(JacksonMapper.marshall(new EndpointDTO(name, uri, account, tag)))
-				.auth()
-				.oauth2("token123")
-				.contentType(ContentType.JSON);
-
-	}
-
-	@When("User send create new endpoint request")
-	public void userSendCreateNewEndpoint() {
-		response = request.post(API_URI + "endpoint");
-	}
-
-	@Given("There is no endpoints in DLab")
-	public void thereIsNoEndpointsInDLab() {
-		MongoDBHelper.cleanCollection("endpoints");
-
-	}
-
-	@Then("Response status code is {int}")
-	public void responseStatusCodeIs(int code) {
-		assertThat(response.getStatusCode(), equalTo(code));
-	}
-
-	@And("Endpoint URI is present in location header")
-	public void endpointURIIsPresentInLocationHeader() {
-		assertThat(response.getHeader("Location"), equalTo(API_URI + "endpoint/" + name));
-	}
-
-	@When("User try to get information about endpoint with name {string}")
-	public void userTryToGetInformationAboutEndpointWithName(String endpoint) throws URISyntaxException {
-		response = authenticatedRequest()
-				.get(new URI(API_URI + "endpoint/" + endpoint));
-
-	}
-
-	@And("Endpoint information is successfully returned with " +
-			"name {string}, uri {string}, account {string}, and tag {string}")
-	public void endpointInformationIsSuccessfullyReturnedWithNameUriAccountAndTag(String name, String uri,
-																				  String account, String tag) {
-		final EndpointDTO dto = response.getBody().as(EndpointDTO.class);
-		assertThat(dto.getAccount(), equalTo(account));
-		assertThat(dto.getName(), equalTo(name));
-		assertThat(dto.getUrl(), equalTo(uri));
-		assertThat(dto.getTag(), equalTo(tag));
-
-	}
-
-	@When("User try to get information about endpoints")
-	public void userTryToGetInformationAboutEndpoints() throws URISyntaxException {
-		response = authenticatedRequest()
-				.get(new URI(API_URI + "endpoint"));
-
-	}
-
-	@And("There are endpoints with name test1 and test2")
-	public void thereAreEndpointsWithNameTestAndTest() {
-		final EndpointDTO[] endpoints = response.getBody().as(EndpointDTO[].class);
-		assertThat(2, equalTo(endpoints.length));
-		assertThat("test1", equalTo(endpoints[0].getName()));
-		assertThat("test2", equalTo(endpoints[1].getName()));
-	}
-
-	private RequestSpecification authenticatedRequest() {
-		return given()
-				.auth()
-				.oauth2("token123");
-	}
-}
diff --git a/integration-tests-cucumber/src/test/java/dlab/login/LoginSteps.java b/integration-tests-cucumber/src/test/java/dlab/login/LoginSteps.java
deleted file mode 100644
index fd533e0..0000000
--- a/integration-tests-cucumber/src/test/java/dlab/login/LoginSteps.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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 dlab.login;
-
-import com.jayway.restassured.http.ContentType;
-import com.jayway.restassured.response.Response;
-import com.jayway.restassured.specification.RequestSpecification;
-import cucumber.api.java.en.Given;
-import cucumber.api.java.en.Then;
-import cucumber.api.java.en.When;
-import gherkin.deps.com.google.gson.JsonObject;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import static com.jayway.restassured.RestAssured.given;
-import static dlab.Constants.API_URI;
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.assertThat;
-
-public class LoginSteps {
-
-
-	private static final String LOGIN_RESOURCE_PATH = API_URI + "user/login";
-	private RequestSpecification request;
-	private Response response;
-
-	@Given("User try to login to Dlab with {string} and {string}")
-	public void userProvidedLoginAndPassword(String username, String password) {
-		JsonObject jsonObject = new JsonObject();
-		jsonObject.addProperty("username", username);
-		jsonObject.addProperty("password", password);
-		request = given().body(jsonObject.toString()).contentType(ContentType.JSON);
-	}
-
-	@When("user try to login")
-	public void userTryToLogin() throws URISyntaxException {
-		response = request.post(new URI(LOGIN_RESOURCE_PATH));
-	}
-
-	@Then("response code is {string}")
-	public void responseCodeIs(String status) {
-		assertThat(response.getStatusCode(), equalTo(Integer.valueOf(status)));
-
-	}
-}
diff --git a/integration-tests-cucumber/src/test/resources/config.properties b/integration-tests-cucumber/src/test/resources/config.properties
index d0cfc24..e1a45b9 100644
--- a/integration-tests-cucumber/src/test/resources/config.properties
+++ b/integration-tests-cucumber/src/test/resources/config.properties
@@ -16,5 +16,5 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-mongo.connection.string=mongodb://localhost:27017/DLAB
-mongo.db.name=DLAB
\ No newline at end of file
+mongo.connection.string=mongodb://localhost:27017/DATALAB
+mongo.db.name=DATALAB
\ No newline at end of file
diff --git a/integration-tests-cucumber/src/test/resources/datalab/endpoint.feature b/integration-tests-cucumber/src/test/resources/datalab/endpoint.feature
new file mode 100644
index 0000000..0cca194
--- /dev/null
+++ b/integration-tests-cucumber/src/test/resources/datalab/endpoint.feature
@@ -0,0 +1,75 @@
+#
+# 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.
+#
+Feature: Endpoint management in DataLab
+  Such feature allowed to manage endpoint inside DataLab
+
+  Scenario Outline: Create new endpoint when it does not exist
+
+    Given There is no endpoints in DataLab
+    And User try to create new endpoint with name "<name>" and uri "<uri>" and account "<account>" and "<tag>"
+    When User send create new endpoint request
+    Then Response status code is 200
+    And Endpoint URI is present in location header
+    Examples:
+      | name          | uri     | account   | tag      |
+      | test_endpoint | someuri | 123231312 | some_tag |
+
+
+  Scenario Outline: Create new endpoint when it exist already
+
+    Given There is no endpoints in DataLab
+    And User try to create new endpoint with name "<name>" and uri "<uri>" and account "<account>" and "<tag>"
+    And  User send create new endpoint request
+    When User try to create new endpoint with name "<name>" and uri "<uri>" and account "<account>" and "<tag>"
+    And User send create new endpoint request
+    Then Response status code is 409
+    Examples:
+      | name          | uri     | account   | tag      |
+      | test_endpoint | someuri | 123231312 | some_tag |
+
+
+  Scenario Outline: Get information for endpoint
+
+    Given There is no endpoints in DataLab
+    And User try to create new endpoint with name "<name>" and uri "<uri>" and account "<account>" and "<tag>"
+    And  User send create new endpoint request
+    When User try to get information about endpoint with name "<name>"
+    Then Response status code is 200
+    And Endpoint information is successfully returned with name "<name>", uri "<uri>", account "<account>", and tag "<tag>"
+    Examples:
+      | name          | uri     | account   | tag      |
+      | test_endpoint | someuri | 123231312 | some_tag |
+
+
+  Scenario: Get list of endpoints
+
+    Given There is no endpoints in DataLab
+    And User try to create new endpoint with name "test1" and uri "someuri1" and account "123" and "customTag1"
+    And  User send create new endpoint request
+    And User try to create new endpoint with name "test2" and uri "someuri2" and account "1233" and "customTag4"
+    And  User send create new endpoint request
+    When User try to get information about endpoints
+    Then Response status code is 200
+    And There are endpoints with name test1 and test2
+
+  Scenario: Get not endpoint that does not exist
+
+    Given There is no endpoints in DataLab
+    When User try to get information about endpoint with name "someName"
+    Then Response status code is 404
diff --git a/integration-tests-cucumber/src/test/resources/datalab/login.feature b/integration-tests-cucumber/src/test/resources/datalab/login.feature
new file mode 100644
index 0000000..243a6f3
--- /dev/null
+++ b/integration-tests-cucumber/src/test/resources/datalab/login.feature
@@ -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.
+#
+Feature: DataLab login API
+  Used to check DataLab login flow
+
+  Scenario Outline: User try to login to DataLab
+    Given User try to login to Datalab with "<username>" and "<password>"
+    When user try to login
+    Then response code is "<status>"
+
+    Examples:
+      | username       | password | status |
+      | test           | pass     | 200    |
+      | not_valid_user | pass     | 401    |
\ No newline at end of file
diff --git a/integration-tests-cucumber/src/test/resources/dlab/endpoint.feature b/integration-tests-cucumber/src/test/resources/dlab/endpoint.feature
deleted file mode 100644
index 1f7fe14..0000000
--- a/integration-tests-cucumber/src/test/resources/dlab/endpoint.feature
+++ /dev/null
@@ -1,75 +0,0 @@
-#
-# 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.
-#
-Feature: Endpoint management in DLab
-  Such feature allowed to manage endpoint inside DLab
-
-  Scenario Outline: Create new endpoint when it does not exist
-
-    Given There is no endpoints in DLab
-    And User try to create new endpoint with name "<name>" and uri "<uri>" and account "<account>" and "<tag>"
-    When User send create new endpoint request
-    Then Response status code is 200
-    And Endpoint URI is present in location header
-    Examples:
-      | name          | uri     | account   | tag      |
-      | test_endpoint | someuri | 123231312 | some_tag |
-
-
-  Scenario Outline: Create new endpoint when it exist already
-
-    Given There is no endpoints in DLab
-    And User try to create new endpoint with name "<name>" and uri "<uri>" and account "<account>" and "<tag>"
-    And  User send create new endpoint request
-    When User try to create new endpoint with name "<name>" and uri "<uri>" and account "<account>" and "<tag>"
-    And User send create new endpoint request
-    Then Response status code is 409
-    Examples:
-      | name          | uri     | account   | tag      |
-      | test_endpoint | someuri | 123231312 | some_tag |
-
-
-  Scenario Outline: Get information for endpoint
-
-    Given There is no endpoints in DLab
-    And User try to create new endpoint with name "<name>" and uri "<uri>" and account "<account>" and "<tag>"
-    And  User send create new endpoint request
-    When User try to get information about endpoint with name "<name>"
-    Then Response status code is 200
-    And Endpoint information is successfully returned with name "<name>", uri "<uri>", account "<account>", and tag "<tag>"
-    Examples:
-      | name          | uri     | account   | tag      |
-      | test_endpoint | someuri | 123231312 | some_tag |
-
-
-  Scenario: Get list of endpoints
-
-    Given There is no endpoints in DLab
-    And User try to create new endpoint with name "test1" and uri "someuri1" and account "123" and "customTag1"
-    And  User send create new endpoint request
-    And User try to create new endpoint with name "test2" and uri "someuri2" and account "1233" and "customTag4"
-    And  User send create new endpoint request
-    When User try to get information about endpoints
-    Then Response status code is 200
-    And There are endpoints with name test1 and test2
-
-  Scenario: Get not endpoint that does not exist
-
-    Given There is no endpoints in DLab
-    When User try to get information about endpoint with name "someName"
-    Then Response status code is 404
diff --git a/integration-tests-cucumber/src/test/resources/dlab/login.feature b/integration-tests-cucumber/src/test/resources/dlab/login.feature
deleted file mode 100644
index 1675aad..0000000
--- a/integration-tests-cucumber/src/test/resources/dlab/login.feature
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-# 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.
-#
-Feature: DLab login API
-  Used to check DLab login flow
-
-  Scenario Outline: User try to login to DLab
-    Given User try to login to Dlab with "<username>" and "<password>"
-    When user try to login
-    Then response code is "<status>"
-
-    Examples:
-      | username       | password | status |
-      | test           | pass     | 200    |
-      | not_valid_user | pass     | 401    |
\ No newline at end of file
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index 9ac5284..5b3e753 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -180,7 +180,7 @@
     </dependencies>
 
     <build>
-    	<finalName>${project.artifactId}-${dlab.version}</finalName>
+        <finalName>${project.artifactId}-${datalab.version}</finalName>
         <plugins>
             <plugin>
                 <artifactId>maven-compiler-plugin</artifactId>
@@ -188,7 +188,7 @@
                 <configuration>
                     <source>${java.version}</source>
                     <target>${java.version}</target>
-                    
+
                 </configuration>
             </plugin>
             
@@ -248,17 +248,17 @@
                                 <transformer
                                         implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
 <!--                                     <mainClass>com.epam.dlab.automation</mainClass> -->
-									<manifestEntries>
-										<Created-By>&lt;EPAM&gt; Systems</Created-By>
-										<Name>com/epam/dlab/automation</Name>
-										<Implementation-Title>DLab Integration Tests</Implementation-Title>
-										<Implementation-Version>${dlab.version}</Implementation-Version>
-										<Implementation-Vendor>&lt;EPAM&gt; Systems</Implementation-Vendor>
-										<Build-Time>${maven.build.timestamp}</Build-Time>
-										<Build-OS>${os.name}</Build-OS>
-										<GIT-Branch>${scmBranch}</GIT-Branch>
-										<GIT-Commit>${buildNumber}</GIT-Commit>
-									</manifestEntries>
+                                    <manifestEntries>
+                                        <Created-By>&lt;EPAM&gt; Systems</Created-By>
+                                        <Name>com/epam/dlab/automation</Name>
+                                        <Implementation-Title>DLab Integration Tests</Implementation-Title>
+                                        <Implementation-Version>${datalab.version}</Implementation-Version>
+                                        <Implementation-Vendor>&lt;EPAM&gt; Systems</Implementation-Vendor>
+                                        <Build-Time>${maven.build.timestamp}</Build-Time>
+                                        <Build-OS>${os.name}</Build-OS>
+                                        <GIT-Branch>${scmBranch}</GIT-Branch>
+                                        <GIT-Commit>${buildNumber}</GIT-Commit>
+                                    </manifestEntries>
                                 </transformer>
                             </transformers>
                             <filters>
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/cloud/VirtualMachineStatusChecker.java b/integration-tests/src/main/java/com/epam/dlab/automation/cloud/VirtualMachineStatusChecker.java
index 0ecff1d..79313b3 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/cloud/VirtualMachineStatusChecker.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/cloud/VirtualMachineStatusChecker.java
@@ -17,15 +17,15 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.cloud;
+package com.epam.datalab.automation.cloud;
 
-import com.epam.dlab.automation.cloud.aws.AmazonHelper;
-import com.epam.dlab.automation.cloud.aws.AmazonInstanceState;
-import com.epam.dlab.automation.cloud.azure.AzureHelper;
-import com.epam.dlab.automation.cloud.gcp.GcpHelper;
-import com.epam.dlab.automation.cloud.gcp.GcpInstanceState;
-import com.epam.dlab.automation.helper.CloudProvider;
-import com.epam.dlab.automation.helper.ConfigPropertyValue;
+import com.epam.datalab.automation.cloud.aws.AmazonHelper;
+import com.epam.datalab.automation.cloud.aws.AmazonInstanceState;
+import com.epam.datalab.automation.cloud.azure.AzureHelper;
+import com.epam.datalab.automation.cloud.gcp.GcpHelper;
+import com.epam.datalab.automation.cloud.gcp.GcpInstanceState;
+import com.epam.datalab.automation.helper.CloudProvider;
+import com.epam.datalab.automation.helper.ConfigPropertyValue;
 import com.microsoft.azure.management.compute.PowerState;
 import org.testng.Assert;
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/cloud/aws/AmazonHelper.java b/integration-tests/src/main/java/com/epam/dlab/automation/cloud/aws/AmazonHelper.java
index 117f3ee..c5cc69f 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/cloud/aws/AmazonHelper.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/cloud/aws/AmazonHelper.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.cloud.aws;
+package com.epam.datalab.automation.cloud.aws;
 
 import com.amazonaws.auth.AWSCredentials;
 import com.amazonaws.auth.BasicAWSCredentials;
@@ -30,9 +30,9 @@
 import com.amazonaws.services.s3.AmazonS3Client;
 import com.amazonaws.services.s3.model.AccessControlList;
 import com.amazonaws.services.s3.model.Grant;
-import com.epam.dlab.automation.exceptions.CloudException;
-import com.epam.dlab.automation.helper.ConfigPropertyValue;
-import com.epam.dlab.automation.helper.NamingHelper;
+import com.epam.datalab.automation.exceptions.CloudException;
+import com.epam.datalab.automation.helper.ConfigPropertyValue;
+import com.epam.datalab.automation.helper.NamingHelper;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.testng.Assert;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/cloud/aws/AmazonInstanceState.java b/integration-tests/src/main/java/com/epam/dlab/automation/cloud/aws/AmazonInstanceState.java
index 576be9d..2d49bec 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/cloud/aws/AmazonInstanceState.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/cloud/aws/AmazonInstanceState.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.cloud.aws;
+package com.epam.datalab.automation.cloud.aws;
 
 public enum AmazonInstanceState {
     STARTING,
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/cloud/azure/AzureHelper.java b/integration-tests/src/main/java/com/epam/dlab/automation/cloud/azure/AzureHelper.java
index 25fb388..79c6654 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/cloud/azure/AzureHelper.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/cloud/azure/AzureHelper.java
@@ -17,10 +17,10 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.cloud.azure;
+package com.epam.datalab.automation.cloud.azure;
 
-import com.epam.dlab.automation.exceptions.CloudException;
-import com.epam.dlab.automation.helper.ConfigPropertyValue;
+import com.epam.datalab.automation.exceptions.CloudException;
+import com.epam.datalab.automation.helper.ConfigPropertyValue;
 import com.microsoft.azure.management.Azure;
 import com.microsoft.azure.management.compute.PowerState;
 import com.microsoft.azure.management.compute.VirtualMachine;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/cloud/gcp/GcpHelper.java b/integration-tests/src/main/java/com/epam/dlab/automation/cloud/gcp/GcpHelper.java
index 7240464..b796510 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/cloud/gcp/GcpHelper.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/cloud/gcp/GcpHelper.java
@@ -17,10 +17,10 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.cloud.gcp;
+package com.epam.datalab.automation.cloud.gcp;
 
-import com.epam.dlab.automation.exceptions.CloudException;
-import com.epam.dlab.automation.helper.ConfigPropertyValue;
+import com.epam.datalab.automation.exceptions.CloudException;
+import com.epam.datalab.automation.helper.ConfigPropertyValue;
 import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
 import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
 import com.google.api.client.http.HttpTransport;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/cloud/gcp/GcpInstanceState.java b/integration-tests/src/main/java/com/epam/dlab/automation/cloud/gcp/GcpInstanceState.java
index 5c084c1..7d0207a 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/cloud/gcp/GcpInstanceState.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/cloud/gcp/GcpInstanceState.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.cloud.gcp;
+package com.epam.datalab.automation.cloud.gcp;
 
 public enum GcpInstanceState {
 	STARTING,
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/docker/AckStatus.java b/integration-tests/src/main/java/com/epam/dlab/automation/docker/AckStatus.java
index df4b7e7..16dee01 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/docker/AckStatus.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/docker/AckStatus.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.docker;
+package com.epam.datalab.automation.docker;
 
 public class AckStatus {
     private int status;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/docker/Bridge.java b/integration-tests/src/main/java/com/epam/dlab/automation/docker/Bridge.java
index 8cc6015..5a7ef0e 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/docker/Bridge.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/docker/Bridge.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.docker;
+package com.epam.datalab.automation.docker;
 
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/docker/Docker.java b/integration-tests/src/main/java/com/epam/dlab/automation/docker/Docker.java
index 012edaf..3d52598 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/docker/Docker.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/docker/Docker.java
@@ -17,10 +17,10 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.docker;
+package com.epam.datalab.automation.docker;
 
-import com.epam.dlab.automation.exceptions.DockerException;
-import com.epam.dlab.automation.helper.ConfigPropertyValue;
+import com.epam.datalab.automation.exceptions.DockerException;
+import com.epam.datalab.automation.helper.ConfigPropertyValue;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.jcraft.jsch.ChannelExec;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/docker/DockerContainer.java b/integration-tests/src/main/java/com/epam/dlab/automation/docker/DockerContainer.java
index c22a688..f0c0c9e 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/docker/DockerContainer.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/docker/DockerContainer.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.docker;
+package com.epam.datalab.automation.docker;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/docker/HostConfig.java b/integration-tests/src/main/java/com/epam/dlab/automation/docker/HostConfig.java
index c2d5db0..a5a0adb 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/docker/HostConfig.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/docker/HostConfig.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.docker;
+package com.epam.datalab.automation.docker;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/docker/Labels.java b/integration-tests/src/main/java/com/epam/dlab/automation/docker/Labels.java
index 1e49a60..adbfe31 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/docker/Labels.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/docker/Labels.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.docker;
+package com.epam.datalab.automation.docker;
 
 class Labels {
 }
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/docker/NetworkSettings.java b/integration-tests/src/main/java/com/epam/dlab/automation/docker/NetworkSettings.java
index 295c217..d21e52e 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/docker/NetworkSettings.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/docker/NetworkSettings.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.docker;
+package com.epam.datalab.automation.docker;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/docker/Networks.java b/integration-tests/src/main/java/com/epam/dlab/automation/docker/Networks.java
index 2679fa3..2ea6542 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/docker/Networks.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/docker/Networks.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.docker;
+package com.epam.datalab.automation.docker;
 
 public class Networks {
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/docker/SSHConnect.java b/integration-tests/src/main/java/com/epam/dlab/automation/docker/SSHConnect.java
index fa369fa..6d498f3 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/docker/SSHConnect.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/docker/SSHConnect.java
@@ -17,9 +17,9 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.docker;
+package com.epam.datalab.automation.docker;
 
-import com.epam.dlab.automation.helper.ConfigPropertyValue;
+import com.epam.datalab.automation.helper.ConfigPropertyValue;
 import com.jcraft.jsch.*;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/CloudException.java b/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/CloudException.java
index b576931..f440c39 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/CloudException.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/CloudException.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.exceptions;
+package com.epam.datalab.automation.exceptions;
 
 public class CloudException extends RuntimeException {
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/DockerException.java b/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/DockerException.java
index ae8d7df..69b6f13 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/DockerException.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/DockerException.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.exceptions;
+package com.epam.datalab.automation.exceptions;
 
 public class DockerException extends RuntimeException {
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/JenkinsException.java b/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/JenkinsException.java
index 4b70836..0171ce9 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/JenkinsException.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/JenkinsException.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.exceptions;
+package com.epam.datalab.automation.exceptions;
 
 public class JenkinsException extends RuntimeException {
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/LoadFailException.java b/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/LoadFailException.java
index 16d4f20..875e9f1 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/LoadFailException.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/exceptions/LoadFailException.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.exceptions;
+package com.epam.datalab.automation.exceptions;
 
 public class LoadFailException extends RuntimeException {
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/helper/CloudHelper.java b/integration-tests/src/main/java/com/epam/dlab/automation/helper/CloudHelper.java
index 4e0894f..3917764 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/helper/CloudHelper.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/helper/CloudHelper.java
@@ -17,18 +17,18 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.helper;
+package com.epam.datalab.automation.helper;
 
 import com.amazonaws.services.ec2.model.Instance;
 import com.amazonaws.services.ec2.model.Tag;
-import com.epam.dlab.automation.cloud.aws.AmazonHelper;
-import com.epam.dlab.automation.cloud.azure.AzureHelper;
-import com.epam.dlab.automation.cloud.gcp.GcpHelper;
-import com.epam.dlab.automation.exceptions.CloudException;
-import com.epam.dlab.automation.model.DeployClusterDto;
-import com.epam.dlab.automation.model.DeployDataProcDto;
-import com.epam.dlab.automation.model.DeployEMRDto;
-import com.epam.dlab.automation.model.NotebookConfig;
+import com.epam.datalab.automation.cloud.aws.AmazonHelper;
+import com.epam.datalab.automation.cloud.azure.AzureHelper;
+import com.epam.datalab.automation.cloud.gcp.GcpHelper;
+import com.epam.datalab.automation.exceptions.CloudException;
+import com.epam.datalab.automation.model.DeployClusterDto;
+import com.epam.datalab.automation.model.DeployDataProcDto;
+import com.epam.datalab.automation.model.DeployEMRDto;
+import com.epam.datalab.automation.model.NotebookConfig;
 import org.apache.commons.lang3.StringUtils;
 
 import java.io.IOException;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/helper/CloudProvider.java b/integration-tests/src/main/java/com/epam/dlab/automation/helper/CloudProvider.java
index f5241a4..23163f6 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/helper/CloudProvider.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/helper/CloudProvider.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.helper;
+package com.epam.datalab.automation.helper;
 
 public class CloudProvider {
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/helper/ConfigPropertyValue.java b/integration-tests/src/main/java/com/epam/dlab/automation/helper/ConfigPropertyValue.java
index aeb6036..01e0cdf 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/helper/ConfigPropertyValue.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/helper/ConfigPropertyValue.java
@@ -17,9 +17,9 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.helper;
+package com.epam.datalab.automation.helper;
 
-import com.epam.dlab.automation.exceptions.LoadFailException;
+import com.epam.datalab.automation.exceptions.LoadFailException;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/helper/NamingHelper.java b/integration-tests/src/main/java/com/epam/dlab/automation/helper/NamingHelper.java
index 3094f1c..44fe86e 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/helper/NamingHelper.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/helper/NamingHelper.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.helper;
+package com.epam.datalab.automation.helper;
 
 import java.io.IOException;
 import java.text.SimpleDateFormat;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/helper/PropertiesResolver.java b/integration-tests/src/main/java/com/epam/dlab/automation/helper/PropertiesResolver.java
index f71ccc3..eeabe1b 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/helper/PropertiesResolver.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/helper/PropertiesResolver.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.helper;
+package com.epam.datalab.automation.helper;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/helper/WaitForStatus.java b/integration-tests/src/main/java/com/epam/dlab/automation/helper/WaitForStatus.java
index 4cb4129..bccbef0 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/helper/WaitForStatus.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/helper/WaitForStatus.java
@@ -17,11 +17,11 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.helper;
+package com.epam.datalab.automation.helper;
 
-import com.epam.dlab.automation.http.ContentType;
-import com.epam.dlab.automation.http.HttpRequest;
-import com.epam.dlab.automation.http.HttpStatusCode;
+import com.epam.datalab.automation.http.ContentType;
+import com.epam.datalab.automation.http.HttpRequest;
+import com.epam.datalab.automation.http.HttpStatusCode;
 import com.jayway.restassured.path.json.JsonPath;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/http/ApiPath.java b/integration-tests/src/main/java/com/epam/dlab/automation/http/ApiPath.java
index c3dc9f1..936f464 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/http/ApiPath.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/http/ApiPath.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.http;
+package com.epam.datalab.automation.http;
 
 public class ApiPath {
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/http/ContentType.java b/integration-tests/src/main/java/com/epam/dlab/automation/http/ContentType.java
index e2a482c..93fe54b 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/http/ContentType.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/http/ContentType.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.http;
+package com.epam.datalab.automation.http;
 
 public class ContentType{
     public static final String FORMDATA = "multipart/form-data";
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/http/HttpRequest.java b/integration-tests/src/main/java/com/epam/dlab/automation/http/HttpRequest.java
index 2ef936f..0c9530d 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/http/HttpRequest.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/http/HttpRequest.java
@@ -17,9 +17,9 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.http;
+package com.epam.datalab.automation.http;
 
-import com.epam.dlab.automation.helper.ConfigPropertyValue;
+import com.epam.datalab.automation.helper.ConfigPropertyValue;
 import com.jayway.restassured.http.ContentType;
 import com.jayway.restassured.response.Response;
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/http/HttpStatusCode.java b/integration-tests/src/main/java/com/epam/dlab/automation/http/HttpStatusCode.java
index 6c4aef0..e6e5dad 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/http/HttpStatusCode.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/http/HttpStatusCode.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.http;
+package com.epam.datalab.automation.http;
 
 public class HttpStatusCode {
     
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsConfigProperties.java b/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsConfigProperties.java
index 158715b..9240ea2 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsConfigProperties.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsConfigProperties.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.jenkins;
+package com.epam.datalab.automation.jenkins;
 
 public class JenkinsConfigProperties {
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsResponseElements.java b/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsResponseElements.java
index 0aca9f6..989558e 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsResponseElements.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsResponseElements.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.jenkins;
+package com.epam.datalab.automation.jenkins;
 
 public class JenkinsResponseElements {
 	public static final String IN_QUEUE_ELEMENT = "freeStyleProject.inQueue";
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsService.java b/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsService.java
index 5d2a995..4606f55 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsService.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsService.java
@@ -17,12 +17,12 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.jenkins;
+package com.epam.datalab.automation.jenkins;
 
-import com.epam.dlab.automation.exceptions.JenkinsException;
-import com.epam.dlab.automation.helper.ConfigPropertyValue;
-import com.epam.dlab.automation.helper.NamingHelper;
-import com.epam.dlab.automation.http.HttpStatusCode;
+import com.epam.datalab.automation.exceptions.JenkinsException;
+import com.epam.datalab.automation.helper.ConfigPropertyValue;
+import com.epam.datalab.automation.helper.NamingHelper;
+import com.epam.datalab.automation.http.HttpStatusCode;
 import com.jayway.restassured.RestAssured;
 import com.jayway.restassured.authentication.FormAuthConfig;
 import com.jayway.restassured.http.ContentType;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsUrls.java b/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsUrls.java
index 04bedcc..3e88c55 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsUrls.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/jenkins/JenkinsUrls.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.jenkins;
+package com.epam.datalab.automation.jenkins;
 
 public class JenkinsUrls {
 	public static final String API = "api/xml";
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/model/CreateNotebookDto.java b/integration-tests/src/main/java/com/epam/dlab/automation/model/CreateNotebookDto.java
index 71bfedf..fc309ba 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/model/CreateNotebookDto.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/model/CreateNotebookDto.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.model;
+package com.epam.datalab.automation.model;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/model/DeployClusterDto.java b/integration-tests/src/main/java/com/epam/dlab/automation/model/DeployClusterDto.java
index 695a5eb..1282972 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/model/DeployClusterDto.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/model/DeployClusterDto.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.model;
+package com.epam.datalab.automation.model;
 
 
 import com.fasterxml.jackson.annotation.JsonProperty;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/model/DeployDataProcDto.java b/integration-tests/src/main/java/com/epam/dlab/automation/model/DeployDataProcDto.java
index b3b64e2..5448a6c 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/model/DeployDataProcDto.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/model/DeployDataProcDto.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.model;
+package com.epam.datalab.automation.model;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.MoreObjects;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/model/DeployEMRDto.java b/integration-tests/src/main/java/com/epam/dlab/automation/model/DeployEMRDto.java
index 8f3ac1e..2e43a2b 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/model/DeployEMRDto.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/model/DeployEMRDto.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.model;
+package com.epam.datalab.automation.model;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.MoreObjects;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/model/DeploySparkDto.java b/integration-tests/src/main/java/com/epam/dlab/automation/model/DeploySparkDto.java
index d1b4734..445880f 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/model/DeploySparkDto.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/model/DeploySparkDto.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.model;
+package com.epam.datalab.automation.model;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.MoreObjects;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/model/ExploratoryImageDto.java b/integration-tests/src/main/java/com/epam/dlab/automation/model/ExploratoryImageDto.java
index 84950df..72e5a90 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/model/ExploratoryImageDto.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/model/ExploratoryImageDto.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.model;
+package com.epam.datalab.automation.model;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/model/ImageDto.java b/integration-tests/src/main/java/com/epam/dlab/automation/model/ImageDto.java
index 0a5dc0b..3d7a0df 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/model/ImageDto.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/model/ImageDto.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.model;
+package com.epam.datalab.automation.model;
 
 public class ImageDto {
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/model/JsonMapperDto.java b/integration-tests/src/main/java/com/epam/dlab/automation/model/JsonMapperDto.java
index 11cdd50..9f38008 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/model/JsonMapperDto.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/model/JsonMapperDto.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.model;
+package com.epam.datalab.automation.model;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.type.CollectionType;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/model/Lib.java b/integration-tests/src/main/java/com/epam/dlab/automation/model/Lib.java
index a804c18..d86adff 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/model/Lib.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/model/Lib.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.model;
+package com.epam.datalab.automation.model;
 
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/model/LoginDto.java b/integration-tests/src/main/java/com/epam/dlab/automation/model/LoginDto.java
index 4018643..6130a02 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/model/LoginDto.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/model/LoginDto.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.model;
+package com.epam.datalab.automation.model;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 
diff --git a/integration-tests/src/main/java/com/epam/dlab/automation/model/NotebookConfig.java b/integration-tests/src/main/java/com/epam/dlab/automation/model/NotebookConfig.java
index bac7893..a788f87 100644
--- a/integration-tests/src/main/java/com/epam/dlab/automation/model/NotebookConfig.java
+++ b/integration-tests/src/main/java/com/epam/dlab/automation/model/NotebookConfig.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.model;
+package com.epam.datalab.automation.model;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.MoreObjects;
diff --git a/integration-tests/src/main/resources/log4j2.xml b/integration-tests/src/main/resources/log4j2.xml
index 8c91840..02f1c6f 100644
--- a/integration-tests/src/main/resources/log4j2.xml
+++ b/integration-tests/src/main/resources/log4j2.xml
@@ -50,14 +50,14 @@
 
 
 	<Loggers>
-		<Root level="info">
-			<AppenderRef ref="file" />
-			<AppenderRef ref="console" />
-		</Root>
-		<Logger name="com.epam.dlab.automation" level="debug" additivity="false">
-			<AppenderRef ref="file" />
-			<AppenderRef ref="console" />
-    	</Logger>
-	</Loggers>
+        <Root level="info">
+            <AppenderRef ref="file"/>
+            <AppenderRef ref="console"/>
+        </Root>
+        <Logger name="com.epam.datalab.automation" level="debug" additivity="false">
+            <AppenderRef ref="file"/>
+            <AppenderRef ref="console"/>
+        </Logger>
+    </Loggers>
 
 </Configuration>
\ No newline at end of file
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/TestCallable.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/TestCallable.java
index 881b69e..de0de05 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/TestCallable.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/TestCallable.java
@@ -17,22 +17,22 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test;
+package com.epam.datalab.automation.test;
 
-import com.epam.dlab.automation.cloud.VirtualMachineStatusChecker;
-import com.epam.dlab.automation.cloud.aws.AmazonHelper;
-import com.epam.dlab.automation.docker.Docker;
-import com.epam.dlab.automation.helper.*;
-import com.epam.dlab.automation.http.ApiPath;
-import com.epam.dlab.automation.http.ContentType;
-import com.epam.dlab.automation.http.HttpRequest;
-import com.epam.dlab.automation.http.HttpStatusCode;
-import com.epam.dlab.automation.model.*;
-import com.epam.dlab.automation.test.libs.LibsHelper;
-import com.epam.dlab.automation.test.libs.TestLibGroupStep;
-import com.epam.dlab.automation.test.libs.TestLibInstallStep;
-import com.epam.dlab.automation.test.libs.TestLibListStep;
-import com.epam.dlab.automation.test.libs.models.LibToSearchData;
+import com.epam.datalab.automation.cloud.VirtualMachineStatusChecker;
+import com.epam.datalab.automation.cloud.aws.AmazonHelper;
+import com.epam.datalab.automation.docker.Docker;
+import com.epam.datalab.automation.helper.*;
+import com.epam.datalab.automation.http.ApiPath;
+import com.epam.datalab.automation.http.ContentType;
+import com.epam.datalab.automation.http.HttpRequest;
+import com.epam.datalab.automation.http.HttpStatusCode;
+import com.epam.datalab.automation.model.*;
+import com.epam.datalab.automation.test.libs.LibsHelper;
+import com.epam.datalab.automation.test.libs.TestLibGroupStep;
+import com.epam.datalab.automation.test.libs.TestLibInstallStep;
+import com.epam.datalab.automation.test.libs.TestLibListStep;
+import com.epam.datalab.automation.test.libs.models.LibToSearchData;
 import com.jayway.restassured.response.Response;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/TestDataEngineService.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/TestDataEngineService.java
index ad73842..f828a75 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/TestDataEngineService.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/TestDataEngineService.java
@@ -17,14 +17,14 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test;
+package com.epam.datalab.automation.test;
 
-import com.epam.dlab.automation.docker.AckStatus;
-import com.epam.dlab.automation.docker.SSHConnect;
-import com.epam.dlab.automation.helper.CloudHelper;
-import com.epam.dlab.automation.helper.ConfigPropertyValue;
-import com.epam.dlab.automation.helper.NamingHelper;
-import com.epam.dlab.automation.helper.PropertiesResolver;
+import com.epam.datalab.automation.docker.AckStatus;
+import com.epam.datalab.automation.docker.SSHConnect;
+import com.epam.datalab.automation.helper.CloudHelper;
+import com.epam.datalab.automation.helper.ConfigPropertyValue;
+import com.epam.datalab.automation.helper.NamingHelper;
+import com.epam.datalab.automation.helper.PropertiesResolver;
 import com.jcraft.jsch.*;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/TestServices.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/TestServices.java
index 8d9aad4..801bee1 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/TestServices.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/TestServices.java
@@ -17,19 +17,19 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test;
+package com.epam.datalab.automation.test;
 
-import com.epam.dlab.automation.cloud.VirtualMachineStatusChecker;
-import com.epam.dlab.automation.docker.Docker;
-import com.epam.dlab.automation.helper.*;
-import com.epam.dlab.automation.http.ApiPath;
-import com.epam.dlab.automation.http.ContentType;
-import com.epam.dlab.automation.http.HttpRequest;
-import com.epam.dlab.automation.http.HttpStatusCode;
-import com.epam.dlab.automation.jenkins.JenkinsService;
-import com.epam.dlab.automation.model.Lib;
-import com.epam.dlab.automation.model.LoginDto;
-import com.epam.dlab.automation.model.NotebookConfig;
+import com.epam.datalab.automation.cloud.VirtualMachineStatusChecker;
+import com.epam.datalab.automation.docker.Docker;
+import com.epam.datalab.automation.helper.*;
+import com.epam.datalab.automation.http.ApiPath;
+import com.epam.datalab.automation.http.ContentType;
+import com.epam.datalab.automation.http.HttpRequest;
+import com.epam.datalab.automation.http.HttpStatusCode;
+import com.epam.datalab.automation.jenkins.JenkinsService;
+import com.epam.datalab.automation.model.Lib;
+import com.epam.datalab.automation.model.LoginDto;
+import com.epam.datalab.automation.model.NotebookConfig;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.jayway.restassured.RestAssured;
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/LibraryNotFoundException.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/LibraryNotFoundException.java
index b8fca93..c6d8df1 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/LibraryNotFoundException.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/LibraryNotFoundException.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test.libs;
+package com.epam.datalab.automation.test.libs;
 
 class LibraryNotFoundException extends RuntimeException {
 
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/LibsHelper.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/LibsHelper.java
index 471679c..70fa2b7 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/LibsHelper.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/LibsHelper.java
@@ -17,11 +17,11 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test.libs;
+package com.epam.datalab.automation.test.libs;
 
-import com.epam.dlab.automation.helper.NamingHelper;
+import com.epam.datalab.automation.helper.NamingHelper;
 
-import static com.epam.dlab.automation.helper.NamingHelper.*;
+import static com.epam.datalab.automation.helper.NamingHelper.*;
 
 public class LibsHelper {
 
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestDescription.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestDescription.java
index 5c156b4..dfe5b22 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestDescription.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestDescription.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test.libs;
+package com.epam.datalab.automation.test.libs;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibGroupStep.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibGroupStep.java
index 57d56d4..afecccf 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibGroupStep.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibGroupStep.java
@@ -17,13 +17,13 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test.libs;
+package com.epam.datalab.automation.test.libs;
 
-import com.epam.dlab.automation.helper.ConfigPropertyValue;
-import com.epam.dlab.automation.helper.NamingHelper;
-import com.epam.dlab.automation.http.HttpRequest;
-import com.epam.dlab.automation.http.HttpStatusCode;
-import com.epam.dlab.automation.model.JsonMapperDto;
+import com.epam.datalab.automation.helper.ConfigPropertyValue;
+import com.epam.datalab.automation.helper.NamingHelper;
+import com.epam.datalab.automation.http.HttpRequest;
+import com.epam.datalab.automation.http.HttpStatusCode;
+import com.epam.datalab.automation.model.JsonMapperDto;
 import com.jayway.restassured.response.Response;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibInstallStep.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibInstallStep.java
index 9b9d521..7fa95e7 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibInstallStep.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibInstallStep.java
@@ -17,17 +17,17 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test.libs;
+package com.epam.datalab.automation.test.libs;
 
-import com.epam.dlab.automation.helper.ConfigPropertyValue;
-import com.epam.dlab.automation.helper.NamingHelper;
-import com.epam.dlab.automation.http.ContentType;
-import com.epam.dlab.automation.http.HttpRequest;
-import com.epam.dlab.automation.http.HttpStatusCode;
-import com.epam.dlab.automation.model.Lib;
-import com.epam.dlab.automation.test.libs.models.LibInstallRequest;
-import com.epam.dlab.automation.test.libs.models.LibStatusResponse;
-import com.epam.dlab.automation.test.libs.models.LibraryStatus;
+import com.epam.datalab.automation.helper.ConfigPropertyValue;
+import com.epam.datalab.automation.helper.NamingHelper;
+import com.epam.datalab.automation.http.ContentType;
+import com.epam.datalab.automation.http.HttpRequest;
+import com.epam.datalab.automation.http.HttpStatusCode;
+import com.epam.datalab.automation.model.Lib;
+import com.epam.datalab.automation.test.libs.models.LibInstallRequest;
+import com.epam.datalab.automation.test.libs.models.LibStatusResponse;
+import com.epam.datalab.automation.test.libs.models.LibraryStatus;
 import com.jayway.restassured.response.Response;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibListStep.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibListStep.java
index 89566c2..67d1138 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibListStep.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibListStep.java
@@ -17,16 +17,16 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test.libs;
+package com.epam.datalab.automation.test.libs;
 
-import com.epam.dlab.automation.helper.ConfigPropertyValue;
-import com.epam.dlab.automation.helper.NamingHelper;
-import com.epam.dlab.automation.http.ContentType;
-import com.epam.dlab.automation.http.HttpRequest;
-import com.epam.dlab.automation.http.HttpStatusCode;
-import com.epam.dlab.automation.model.Lib;
-import com.epam.dlab.automation.test.libs.models.LibSearchRequest;
-import com.epam.dlab.automation.test.libs.models.LibToSearchData;
+import com.epam.datalab.automation.helper.ConfigPropertyValue;
+import com.epam.datalab.automation.helper.NamingHelper;
+import com.epam.datalab.automation.http.ContentType;
+import com.epam.datalab.automation.http.HttpRequest;
+import com.epam.datalab.automation.http.HttpStatusCode;
+import com.epam.datalab.automation.model.Lib;
+import com.epam.datalab.automation.test.libs.models.LibSearchRequest;
+import com.epam.datalab.automation.test.libs.models.LibToSearchData;
 import com.jayway.restassured.response.Response;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibStep.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibStep.java
index 5930f77..b93b1bc 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibStep.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/TestLibStep.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test.libs;
+package com.epam.datalab.automation.test.libs;
 
 import java.lang.annotation.Annotation;
 import java.util.concurrent.TimeUnit;
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibInstallRequest.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibInstallRequest.java
index ad48b07..6898d31 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibInstallRequest.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibInstallRequest.java
@@ -17,9 +17,9 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test.libs.models;
+package com.epam.datalab.automation.test.libs.models;
 
-import com.epam.dlab.automation.model.Lib;
+import com.epam.datalab.automation.model.Lib;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.MoreObjects;
 
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibSearchRequest.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibSearchRequest.java
index 45ffa32..21b5ff5 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibSearchRequest.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibSearchRequest.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test.libs.models;
+package com.epam.datalab.automation.test.libs.models;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.MoreObjects;
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibStatusResponse.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibStatusResponse.java
index cf79d82..a5671f7 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibStatusResponse.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibStatusResponse.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test.libs.models;
+package com.epam.datalab.automation.test.libs.models;
 
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonProperty;
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibToSearchData.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibToSearchData.java
index e6aa205..58849eb 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibToSearchData.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibToSearchData.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test.libs.models;
+package com.epam.datalab.automation.test.libs.models;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 
diff --git a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibraryStatus.java b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibraryStatus.java
index 1be3139..0fc8308 100644
--- a/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibraryStatus.java
+++ b/integration-tests/src/test/java/com/epam/dlab/automation/test/libs/models/LibraryStatus.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package com.epam.dlab.automation.test.libs.models;
+package com.epam.datalab.automation.test.libs.models;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.MoreObjects;
diff --git a/integration-tests/src/test/resources/log4j2.xml b/integration-tests/src/test/resources/log4j2.xml
index 91d23a2..c170968 100644
--- a/integration-tests/src/test/resources/log4j2.xml
+++ b/integration-tests/src/test/resources/log4j2.xml
@@ -50,14 +50,14 @@
 
 
 	<Loggers>
-		<Root level="info">
-			<AppenderRef ref="file" />
-			<AppenderRef ref="console" />
-		</Root>
-		<Logger name="com.epam.dlab.automation" level="debug" additivity="false">
-			<AppenderRef ref="file" />
-			<AppenderRef ref="console" />
-    	</Logger>
-	</Loggers>
+        <Root level="info">
+            <AppenderRef ref="file"/>
+            <AppenderRef ref="console"/>
+        </Root>
+        <Logger name="com.epam.datalab.automation" level="debug" additivity="false">
+            <AppenderRef ref="file"/>
+            <AppenderRef ref="console"/>
+        </Logger>
+    </Loggers>
 
 </Configuration>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 95be206..f625c6b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,8 +22,8 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                    http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
-    <groupId>com.epam.dlab</groupId>
-    <artifactId>dlab</artifactId>
+    <groupId>com.epam.datalab</groupId>
+    <artifactId>datalab</artifactId>
     <version>1.0</version>
     <packaging>pom</packaging>
 
@@ -71,24 +71,24 @@
                     **/*Configuration.java,
                     **/*ApplicationConfiguration.java,
                     **/*Application.java,
-                    src/main/java/com/epam/dlab/dto/**,
-                    src/main/java/com/epam/dlab/backendapi/interceptor/**,
-                    src/main/java/com/epam/dlab/backendapi/auth/**,
-                    src/main/java/com/epam/dlab/backendapi/conf/**,
-                    src/main/java/com/epam/dlab/backendapi/domain/**,
-                    src/main/java/com/epam/dlab/backendapi/dropwizard/**,
-                    src/main/java/com/epam/dlab/backendapi/healthcheck/**,
-                    src/main/java/com/epam/dlab/backendapi/modules/**,
-                    src/main/java/com/epam/dlab/backendapi/resources/dto/**,
-                    src/main/java/com/epam/dlab/backendapi/roles/**,
-                    src/main/java/com/epam/dlab/backendapi/servlet/guacamole/**,
-                    src/main/java/com/epam/dlab/backendapi/util/**,
-                    src/main/java/com/epam/dlab/backendapi/validation/**,
-                    src/main/java/com/epam/dlab/backendapi/core/commands/**,
-                    src/main/java/com/epam/dlab/process/**,
-                    src/main/java/com/epam/dlab/backendapi/modules/**,
-                    src/main/java/com/epam/dlab/backendapi/validation/**,
-                    src/main/java/com/epam/dlab/backendapi/schedulers/**
+                    src/main/java/com/epam/datalab/dto/**,
+                    src/main/java/com/epam/datalab/backendapi/interceptor/**,
+                    src/main/java/com/epam/datalab/backendapi/auth/**,
+                    src/main/java/com/epam/datalab/backendapi/conf/**,
+                    src/main/java/com/epam/datalab/backendapi/domain/**,
+                    src/main/java/com/epam/datalab/backendapi/dropwizard/**,
+                    src/main/java/com/epam/datalab/backendapi/healthcheck/**,
+                    src/main/java/com/epam/datalab/backendapi/modules/**,
+                    src/main/java/com/epam/datalab/backendapi/resources/dto/**,
+                    src/main/java/com/epam/datalab/backendapi/roles/**,
+                    src/main/java/com/epam/datalab/backendapi/servlet/guacamole/**,
+                    src/main/java/com/epam/datalab/backendapi/util/**,
+                    src/main/java/com/epam/datalab/backendapi/validation/**,
+                    src/main/java/com/epam/datalab/backendapi/core/commands/**,
+                    src/main/java/com/epam/datalab/process/**,
+                    src/main/java/com/epam/datalab/backendapi/modules/**,
+                    src/main/java/com/epam/datalab/backendapi/validation/**,
+                    src/main/java/com/epam/datalab/backendapi/schedulers/**
                 </sonar.coverage.exclusions>
             </properties>
         </profile>
@@ -98,10 +98,10 @@
         <module>services/common</module>
         <module>services/provisioning-service</module>
         <module>services/self-service</module>
-        <module>services/dlab-model</module>
-        <module>services/dlab-utils</module>
-        <module>services/dlab-webapp-common</module>
-        <module>services/dlab-mongo-migration</module>
+        <module>services/datalab-model</module>
+        <module>services/datalab-utils</module>
+        <module>services/datalab-webapp-common</module>
+        <module>services/datalab-mongo-migration</module>
         <module>services/billing-azure</module>
         <module>services/billing-gcp</module>
         <module>services/billing-aws</module>
@@ -137,7 +137,7 @@
                 <version>1.3</version>
             </dependency>
             <dependency>
-                <groupId>com.epam.dlab</groupId>
+                <groupId>com.epam.datalab</groupId>
                 <artifactId>common</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -191,7 +191,7 @@
     </dependencies>
 
     <build>
-        <finalName>${project.artifactId}-${dlab.version}</finalName>
+        <finalName>${project.artifactId}-${datalab.version}</finalName>
         <pluginManagement>
             <plugins>
                 <plugin>
diff --git a/services/billing-aws/billing.yml b/services/billing-aws/billing.yml
index 3b1943f..cb1d6dc 100644
--- a/services/billing-aws/billing.yml
+++ b/services/billing-aws/billing.yml
@@ -30,7 +30,7 @@
 port: 27017
 username: admin
 password: MONGO_PASSWORD
-database: dlabdb
+database: datalabdb
 
 # Adapter for reading source data. Known types: file, s3file
 adapterIn:
@@ -44,13 +44,13 @@
 
 # Adapter for writing converted data. Known types: console, file, s3file, mongodb
 adapterOut:
-  - type: mongodlab
+  - type: mongodatalab
     host: MONGO_HOST
     port: 27017
     username: admin
     password: MONGO_PASSWORD
-    database: dlabdb
-#    bufferSize: 10000
+    database: datalabdb
+    #    bufferSize: 10000
     upsert: true
     serviceBaseName: SERVICE_BASE_NAME
 
@@ -58,7 +58,7 @@
 filter:
   - type: aws
     currencyCode: USD
-    columnDlabTag: CONF_BILLING_TAG
+    columnDatalabTag: CONF_BILLING_TAG
     serviceBaseName: SERVICE_BASE_NAME
 
 
@@ -68,7 +68,7 @@
     headerLineNo: 1
     skipLines: 1
     columnMapping: >-
-      dlab_id=DLAB_ID;usage_date=USAGE_DATE;product=PRODUCT;
+      datalab_id=DATALAB_ID;usage_date=USAGE_DATE;product=PRODUCT;
       usage_type=USAGE_TYPE;usage=USAGE;cost=COST;
       resource_id=RESOURCE_ID;tags=TAGS
     aggregate: day
@@ -88,7 +88,7 @@
   appenders:
     #- type: console
     - type: file
-      currentLogFilename: /var/opt/dlab/log/ssn/billing.log
+      currentLogFilename: /var/opt/datalab/log/ssn/billing.log
       archive: true
-      archivedLogFilenamePattern: /var/opt/dlab/log/ssn/billing-%d{yyyy-MM-dd}.log.gz
+      archivedLogFilenamePattern: /var/opt/datalab/log/ssn/billing-%d{yyyy-MM-dd}.log.gz
       archivedFileCount: 10
\ No newline at end of file
diff --git a/services/billing-aws/pom.xml b/services/billing-aws/pom.xml
index ec4c830..30226f6 100644
--- a/services/billing-aws/pom.xml
+++ b/services/billing-aws/pom.xml
@@ -23,8 +23,8 @@
                    http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
-        <groupId>com.epam.dlab</groupId>
-        <artifactId>dlab</artifactId>
+        <groupId>com.epam.datalab</groupId>
+        <artifactId>datalab</artifactId>
         <version>1.0</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
@@ -58,7 +58,7 @@
 
     <dependencies>
         <dependency>
-            <groupId>com.epam.dlab</groupId>
+            <groupId>com.epam.datalab</groupId>
             <artifactId>common</artifactId>
         </dependency>
 
@@ -173,8 +173,8 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>dlab-model</artifactId>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>datalab-model</artifactId>
             <version>${project.parent.version}</version>
         </dependency>
 
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/BillingAwsApplication.java b/services/billing-aws/src/main/java/com/epam/datalab/BillingAwsApplication.java
new file mode 100644
index 0000000..c34ad40
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/BillingAwsApplication.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab;
+
+import com.epam.datalab.exceptions.InitializationException;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+
+@SpringBootApplication
+@EnableMongoRepositories
+@EnableConfigurationProperties
+public class BillingAwsApplication {
+
+    public static void main(String[] args) throws InitializationException {
+        SpringApplication.run(BillingAwsApplication.class, args);
+        BillingServiceImpl.startApplication(args);
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/BillingService.java b/services/billing-aws/src/main/java/com/epam/datalab/BillingService.java
new file mode 100644
index 0000000..bfdd4c6
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/BillingService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab;
+
+import com.epam.datalab.dto.billing.BillingData;
+
+import java.util.List;
+
+@FunctionalInterface
+public interface BillingService {
+    List<BillingData> getBillingData();
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/BillingServiceImpl.java b/services/billing-aws/src/main/java/com/epam/datalab/BillingServiceImpl.java
new file mode 100644
index 0000000..25e2fe5
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/BillingServiceImpl.java
@@ -0,0 +1,127 @@
+/*
+ * 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.datalab;
+
+import com.epam.datalab.configuration.BillingToolConfiguration;
+import com.epam.datalab.configuration.BillingToolConfigurationFactory;
+import com.epam.datalab.core.parser.ParserBase;
+import com.epam.datalab.dto.billing.BillingData;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.util.ServiceUtils;
+import org.bson.Document;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.model.aws.ReportLine.FIELD_COST;
+import static com.epam.datalab.model.aws.ReportLine.FIELD_CURRENCY_CODE;
+import static com.epam.datalab.model.aws.ReportLine.FIELD_DATALAB_ID;
+import static com.epam.datalab.model.aws.ReportLine.FIELD_PRODUCT;
+import static com.epam.datalab.model.aws.ReportLine.FIELD_RESOURCE_TYPE;
+import static com.epam.datalab.model.aws.ReportLine.FIELD_USAGE_DATE;
+
+@Service
+public class BillingServiceImpl implements BillingService {
+    private static final Logger LOGGER = LoggerFactory.getLogger(BillingServiceImpl.class);
+    private static BillingToolConfiguration configuration;
+
+    public List<BillingData> getBillingData() {
+        try {
+            ParserBase parser = configuration.build();
+
+            List<BillingData> billingData = parser.parse()
+                    .stream()
+                    .map(this::toBillingData)
+                    .collect(Collectors.toList());
+
+            if (!parser.getStatistics().isEmpty()) {
+                LOGGER.info("Billing report parser statistics:");
+                for (int i = 0; i < parser.getStatistics().size(); i++) {
+                    LOGGER.info("  {}", parser.getStatistics().get(i).toString());
+                }
+            }
+
+            return billingData;
+        } catch (Exception e) {
+            LOGGER.error("Something went wrong ", e);
+            return Collections.emptyList();
+        }
+    }
+
+    private BillingData toBillingData(Document billingData) {
+        return BillingData.builder()
+                .tag(billingData.getString(FIELD_DATALAB_ID).toLowerCase())
+                .usageDateFrom(Optional.ofNullable(billingData.getString(FIELD_USAGE_DATE)).map(LocalDate::parse).orElse(null))
+                .usageDateTo(Optional.ofNullable(billingData.getString(FIELD_USAGE_DATE)).map(LocalDate::parse).orElse(null))
+                .usageDate(billingData.getString(FIELD_USAGE_DATE))
+                .product(billingData.getString(FIELD_PRODUCT))
+                .usageType(billingData.getString(FIELD_RESOURCE_TYPE))
+                .cost(billingData.getDouble(FIELD_COST))
+                .currency(billingData.getString(FIELD_CURRENCY_CODE))
+                .build();
+    }
+
+    public static void initialize(String filename) throws InitializationException {
+        LOGGER.debug("Billing report configuration file: {}", filename);
+        configuration = BillingToolConfigurationFactory.build(filename, BillingToolConfiguration.class);
+    }
+
+    public static void startApplication(String[] args) throws InitializationException {
+        if (ServiceUtils.printAppVersion(BillingTool.class, args)) {
+            return;
+        }
+
+        String confName = null;
+        for (int i = 0; i < args.length; i++) {
+            if (BillingTool.isKey("help", args[i])) {
+                i++;
+                Help.usage(i < args.length ? Arrays.copyOfRange(args, i, args.length) : null);
+                return;
+            } else if (BillingTool.isKey("conf", args[i])) {
+                i++;
+                if (i < args.length) {
+                    confName = args[i];
+                } else {
+                    throw new InitializationException("Missing the name of configuration file");
+                }
+            }
+        }
+
+        if (confName == null) {
+            Help.usage();
+            throw new InitializationException("Missing arguments");
+        }
+
+        BillingTool.setLoggerLevel();
+        try {
+            initialize(confName);
+        } catch (Exception e) {
+            throw new DatalabException("Billing scheduler failed", e);
+        }
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/BillingTool.java b/services/billing-aws/src/main/java/com/epam/datalab/BillingTool.java
new file mode 100644
index 0000000..f334883
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/BillingTool.java
@@ -0,0 +1,176 @@
+/*
+ * 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.datalab;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.LoggerContext;
+import com.epam.datalab.configuration.BillingToolConfiguration;
+import com.epam.datalab.configuration.BillingToolConfigurationFactory;
+import com.epam.datalab.core.parser.ParserBase;
+import com.epam.datalab.exceptions.AdapterException;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.exceptions.ParseException;
+import com.epam.datalab.util.ServiceUtils;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Arrays;
+
+/**
+ * Provides billing parser features.
+ */
+public class BillingTool {
+    private static final Logger LOGGER = LoggerFactory.getLogger(BillingTool.class);
+
+    /**
+     * Runs parser for given configuration.
+     *
+     * @param conf billing configuration.
+     * @throws InitializationException
+     * @throws AdapterException
+     * @throws ParseException
+     */
+    public void run(BillingToolConfiguration conf) throws InitializationException, AdapterException, ParseException {
+        ParserBase parser = conf.build();
+        LOGGER.debug("Billing Tool Configuration: {}", conf);
+        LOGGER.debug("Parser configuration: {}", parser);
+
+        parser.parse();
+        LOGGER.debug("Billing Tool statistics: {}", parser.getStatistics());
+    }
+
+    /**
+     * Runs parser for given configuration in file.
+     *
+     * @param filename the name of file for billing configuration.
+     * @throws InitializationException
+     * @throws AdapterException
+     * @throws ParseException
+     */
+    public void run(String filename) throws InitializationException, AdapterException, ParseException {
+        run(BillingToolConfigurationFactory.build(filename, BillingToolConfiguration.class));
+    }
+
+    /**
+     * Runs parser for given configuration.
+     *
+     * @param jsonNode the billing configuration.
+     * @throws InitializationException
+     * @throws AdapterException
+     * @throws ParseException
+     */
+    public void run(JsonNode jsonNode) throws InitializationException, AdapterException, ParseException {
+        run(BillingToolConfigurationFactory.build(jsonNode, BillingToolConfiguration.class));
+    }
+
+
+    /**
+     * Check the key name for command line.
+     *
+     * @param keyName the name of key.
+     * @param arg     the argument from command line.
+     * @return <b>true</b> if given argument is key.
+     */
+    protected static boolean isKey(String keyName, String arg) {
+        return (("--" + keyName).equalsIgnoreCase(arg) ||
+                ("/" + keyName).equalsIgnoreCase(arg));
+    }
+
+    /**
+     * Set the level of loggers to INFO for external loggers.
+     */
+    protected static void setLoggerLevel() {
+        ch.qos.logback.classic.LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+        ch.qos.logback.classic.Logger logger;
+        String[] loggers = {
+                "org.hibernate",
+                "org.jboss.logging"
+        };
+        for (String name : loggers) {
+            logger = context.getLogger(name);
+            logger.setLevel(Level.INFO);
+        }
+    }
+
+
+    /**
+     * Runs parser for given configuration.
+     *
+     * @param args the arguments of command line.
+     * @throws InitializationException
+     */
+    public static void main(String[] args) throws InitializationException {
+        if (ServiceUtils.printAppVersion(BillingServiceImpl.class, args)) {
+            return;
+        }
+
+        String confName = null;
+        String json = null;
+
+        for (int i = 0; i < args.length; i++) {
+            if (isKey("help", args[i])) {
+                i++;
+                Help.usage(i < args.length ? Arrays.copyOfRange(args, i, args.length) : null);
+                return;
+            } else if (isKey("conf", args[i])) {
+                i++;
+                if (i < args.length) {
+                    confName = args[i];
+                } else {
+                    throw new InitializationException("Missing the name of configuration file");
+                }
+            } else if (isKey("json", args[i])) {
+                i++;
+                if (i < args.length) {
+                    json = args[i];
+                } else {
+                    throw new InitializationException("Missing the content of json configuration");
+                }
+            } else {
+                throw new InitializationException("Unknow argument: " + args[i]);
+            }
+        }
+
+        if (confName == null && json == null) {
+            Help.usage();
+            throw new InitializationException("Missing arguments");
+        }
+
+        if (confName != null && json != null) {
+            Help.usage();
+            throw new InitializationException("Invalid arguments.");
+        }
+
+        setLoggerLevel();
+        try {
+            if (confName != null) {
+                new BillingTool().run(confName);
+            } else {
+                JsonNode jsonNode = new ObjectMapper().valueToTree(json);
+                new BillingTool().run(jsonNode);
+            }
+        } catch (Exception e) {
+            throw new DatalabException("Billing tool failed", e);
+        }
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/Help.java b/services/billing-aws/src/main/java/com/epam/datalab/Help.java
new file mode 100644
index 0000000..08096e6
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/Help.java
@@ -0,0 +1,146 @@
+/*
+ * 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.datalab;
+
+import com.epam.datalab.core.BillingUtils;
+import com.epam.datalab.core.ModuleType;
+import com.epam.datalab.exceptions.InitializationException;
+import com.fasterxml.jackson.annotation.JsonClassDescription;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Print help for billing tool.
+ */
+public class Help {
+
+    private Help() {
+    }
+
+    /**
+     * Print help to console.
+     *
+     * @param resourceName the name of resource.
+     * @param substitute   - map for substitution in help content.
+     * @throws InitializationException
+     */
+    private static void printHelp(String resourceName, Map<String, String> substitute) throws InitializationException {
+        List<String> list = BillingUtils.getResourceAsList("/" + Help.class.getName() + "." + resourceName + ".txt");
+        String help = StringUtils.join(list, System.lineSeparator());
+
+        if (substitute == null) {
+            substitute = new HashMap<>();
+        }
+        substitute.put("classname", BillingServiceImpl.class.getName());
+
+        for (String key : substitute.keySet()) {
+            help = StringUtils.replace(help, "${" + key.toUpperCase() + "}", substitute.get(key));
+        }
+        System.out.println(help);
+    }
+
+    /**
+     * Create and return substitutions for names of modules.
+     *
+     * @return
+     * @throws InitializationException
+     */
+    private static Map<String, String> findModules() throws InitializationException {
+        List<Class<?>> modules = BillingUtils.getModuleClassList();
+        Map<String, String> substitute = new HashMap<>();
+
+        for (Class<?> module : modules) {
+            ModuleType type = BillingUtils.getModuleType(module);
+            JsonTypeName typeName = module.getAnnotation(JsonTypeName.class);
+            if (typeName != null) {
+                String typeNames = substitute.get(type.toString() + "s");
+                typeNames = (typeNames == null ? typeName.value() : typeNames + ", " + typeName.value());
+                substitute.put(type.toString() + "s", typeNames);
+            }
+        }
+
+        return substitute;
+    }
+
+    /**
+     * Find and return help for module.
+     *
+     * @param type the type of module.
+     * @param name the name of module.
+     * @throws InitializationException
+     */
+    private static String findModuleHelp(ModuleType type, String name) throws InitializationException {
+        List<Class<?>> modules = BillingUtils.getModuleClassList();
+        String typeNames = null;
+        for (Class<?> module : modules) {
+            ModuleType t = BillingUtils.getModuleType(module);
+            if (t == type) {
+                JsonTypeName typeName = module.getAnnotation(JsonTypeName.class);
+                if (typeName != null) {
+                    if (name.equals(typeName.value())) {
+                        JsonClassDescription description = module.getAnnotation(JsonClassDescription.class);
+                        if (description != null) {
+                            return description.value();
+                        }
+                        throw new InitializationException("Help for " + type + " " + name + " not found");
+                    } else {
+                        typeNames = (typeNames == null ? typeName.value() : typeNames + ", " + typeName.value());
+                    }
+                }
+            }
+        }
+        throw new InitializationException("Module for " + type + " " + name + " not found." +
+                (typeNames == null ? "" : " Module type must be one of next: " + typeNames));
+    }
+
+    /**
+     * Print help screen for billing tool.
+     *
+     * @throws InitializationException
+     */
+    public static void usage(String... args) throws InitializationException {
+        if (args == null || args.length == 0) {
+            printHelp("usage", null);
+        } else if ("conf".equalsIgnoreCase(args[0])) {
+            printHelp("conf", findModules());
+        } else {
+            ModuleType type = ModuleType.of(args[0]);
+            if (type == null) {
+                System.out.println("Unknown --help " + args[0] + " command.");
+            } else if (args.length < 2) {
+                System.out.println("Missing the type of module.");
+                String typeNames = findModules().get(type.toString() + "s");
+                if (typeNames != null) {
+                    System.out.println("Must be one of next: " + typeNames);
+                }
+            } else if (args.length > 2) {
+                System.out.println("Extra arguments in command: " +
+                        StringUtils.join(Arrays.copyOfRange(args, 2, args.length), " "));
+            } else {
+                System.out.println(findModuleHelp(type, args[1]));
+            }
+        }
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/conf/SecurityConfig.java b/services/billing-aws/src/main/java/com/epam/datalab/conf/SecurityConfig.java
new file mode 100644
index 0000000..d08d5fa
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/conf/SecurityConfig.java
@@ -0,0 +1,66 @@
+/*
+ * 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.datalab.conf;
+
+import org.keycloak.adapters.KeycloakConfigResolver;
+import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
+import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
+import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
+import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
+import org.springframework.security.core.session.SessionRegistryImpl;
+import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
+import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
+
+@KeycloakConfiguration
+class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
+
+    @Autowired
+    public void configureGlobal(AuthenticationManagerBuilder auth) {
+        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
+        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
+        auth.authenticationProvider(keycloakAuthenticationProvider);
+    }
+
+    @Bean
+    public KeycloakConfigResolver keycloakConfigResolver() {
+        return new KeycloakSpringBootConfigResolver();
+    }
+
+    @Bean
+    @Override
+    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
+        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
+    }
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        super.configure(http);
+        http
+                .anonymous().disable()
+                .authorizeRequests()
+                .anyRequest()
+                .authenticated();
+    }
+}
\ No newline at end of file
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/configuration/BillingToolConfiguration.java b/services/billing-aws/src/main/java/com/epam/datalab/configuration/BillingToolConfiguration.java
new file mode 100644
index 0000000..b43031d
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/configuration/BillingToolConfiguration.java
@@ -0,0 +1,282 @@
+/*
+ * 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.datalab.configuration;
+
+import com.epam.datalab.BillingTool;
+import com.epam.datalab.core.AdapterBase;
+import com.epam.datalab.core.AdapterBase.Mode;
+import com.epam.datalab.core.FilterBase;
+import com.epam.datalab.core.ModuleBase;
+import com.epam.datalab.core.ModuleData;
+import com.epam.datalab.core.parser.ParserBase;
+import com.epam.datalab.exceptions.AdapterException;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.mongo.MongoDbConnection;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.ImmutableList;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+/**
+ * Describe configuration for {@link BillingTool}
+ */
+public class BillingToolConfiguration {
+
+    /**
+     * The host name.
+     */
+    @JsonProperty
+    private String host;
+
+    /**
+     * The port.
+     */
+    @JsonProperty
+    private int port;
+
+    /**
+     * The name of database.
+     */
+    @JsonProperty
+    private String database;
+
+    /**
+     * The name of user.
+     */
+    @JsonProperty
+    private String username;
+
+    /**
+     * The password.
+     */
+    @JsonProperty
+    private String password;
+
+    @JsonProperty
+    private boolean billingEnabled;
+
+    /**
+     * Adapter for reading source data.
+     */
+    @Valid
+    @NotNull
+    @JsonProperty
+    private ImmutableList<AdapterBase> adapterIn;
+
+    /**
+     * Adapter for writing converted data.
+     */
+    @Valid
+    @NotNull
+    @JsonProperty
+    private ImmutableList<AdapterBase> adapterOut;
+
+    /**
+     * Parser of source data to common format.
+     */
+    @Valid
+    @NotNull
+    @JsonProperty
+    private ImmutableList<ParserBase> parser;
+
+    /**
+     * Filter for source and converted data.
+     */
+    @Valid
+    @JsonProperty
+    private ImmutableList<FilterBase> filter = null;
+
+    /**
+     * Logging configuration.
+     */
+    @Valid
+    @JsonProperty
+    private LoggingConfigurationFactory logging = null;
+
+
+    /**
+     * Working data of modules.
+     */
+    @JsonIgnore
+    private ModuleData moduleData;
+
+    /**
+     * Return the adapter for reading source data.
+     */
+    public ImmutableList<AdapterBase> getAdapterIn() {
+        return adapterIn;
+    }
+
+    /**
+     * Set the adapter for reading source data.
+     */
+    public void setAdapterIn(ImmutableList<AdapterBase> adapter) {
+        for (AdapterBase a : adapter) {
+            a.setMode(Mode.READ);
+        }
+        this.adapterIn = adapter;
+    }
+
+    /**
+     * Return the adapter for writing converted data.
+     */
+    public ImmutableList<AdapterBase> getAdapterOut() {
+        return adapterOut;
+    }
+
+    /**
+     * Set the adapter for writing converted data.
+     */
+    public void setAdapterOut(ImmutableList<AdapterBase> adapter) {
+        for (AdapterBase a : adapter) {
+            a.setMode(Mode.WRITE);
+        }
+        this.adapterOut = adapter;
+    }
+
+    /**
+     * Return the parser of source data to common format.
+     */
+    public ImmutableList<ParserBase> getParser() {
+        return parser;
+    }
+
+    /**
+     * Set the parser of source data to common format.
+     */
+    public void setParser(ImmutableList<ParserBase> parser) {
+        this.parser = parser;
+    }
+
+    /**
+     * Return the filter for source and converted data.
+     */
+    public ImmutableList<FilterBase> getFilter() {
+        return filter;
+    }
+
+    /**
+     * Set the filter for source and converted data.
+     */
+    public void setFilter(ImmutableList<FilterBase> filter) {
+        this.filter = filter;
+    }
+
+    /**
+     * Return the logging configuration.
+     */
+    public LoggingConfigurationFactory getLogging() {
+        return logging;
+    }
+
+    /**
+     * Set the logging configuration.
+     */
+    public void setLogging(LoggingConfigurationFactory logging) {
+        this.logging = logging;
+    }
+
+
+    /**
+     * Return the working data of modules.
+     */
+    @JsonIgnore
+    public ModuleData getModuleData() {
+        return moduleData;
+    }
+
+    /**
+     * Check and return module.
+     *
+     * @param modules    the list of modules.
+     * @param name       the name of module.
+     * @param isOptional optional module or not.
+     * @return module
+     * @throws InitializationException
+     */
+    private <T extends ModuleBase> T getModule(ImmutableList<T> modules, String name, boolean isOptional) throws
+            InitializationException {
+        T module = (modules != null && modules.size() == 1 ? modules.get(0) : null);
+        if (!isOptional && module == null) {
+            throw new InitializationException("Invalid configuration for property " + name);
+        }
+        return module;
+    }
+
+    /**
+     * Build and return the parser.
+     *
+     * @return the parser.
+     * @throws InitializationException
+     */
+    public ParserBase build() throws InitializationException {
+        ParserBase parserBase = getModule(this.parser, "parser", false);
+        AdapterBase in = getModule(adapterIn, "adapterIn", false);
+        AdapterBase out = getModule(adapterOut, "adapterOut", false);
+        FilterBase f = getModule(filter, "filter", true);
+
+        final MongoDbConnection connection;
+        try {
+            connection = new MongoDbConnection(host, port, database, username, password);
+        } catch (AdapterException e) {
+            throw new InitializationException("Cannot configure mongo connection. " + e.getLocalizedMessage(), e);
+        }
+        moduleData = new ModuleData(connection);
+
+        parserBase.setModuleData(moduleData);
+        in.setModuleData(moduleData);
+        out.setModuleData(moduleData);
+        if (f != null) {
+            f.setModuleData(moduleData);
+        }
+
+        return parserBase.build(in, out, f);
+    }
+
+    public boolean isBillingEnabled() {
+        return billingEnabled;
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @param self the object to generate the string for (typically this), used only for its class name.
+     */
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("moduleData", moduleData)
+                .add("adapterIn", adapterIn)
+                .add("adapterOut", adapterOut)
+                .add("filter", filter)
+                .add("parser", parser)
+                .add("logging", logging)
+                .add("billingEnabled", billingEnabled);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .toString();
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/configuration/BillingToolConfigurationFactory.java b/services/billing-aws/src/main/java/com/epam/datalab/configuration/BillingToolConfigurationFactory.java
new file mode 100644
index 0000000..fac6795
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/configuration/BillingToolConfigurationFactory.java
@@ -0,0 +1,110 @@
+/*
+ * 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.datalab.configuration;
+
+import com.epam.datalab.core.BillingUtils;
+import com.epam.datalab.exceptions.InitializationException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.fasterxml.jackson.datatype.guava.GuavaModule;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Build the instance of class {@link BillingToolConfiguration}.
+ */
+public class BillingToolConfigurationFactory {
+
+    /**
+     * Mapper for reading configuration.
+     */
+    private static ObjectMapper mapper;
+
+    /**
+     * Build the instance of class {@link BillingToolConfiguration} from YAML file.
+     *
+     * @param filename  the name of file.
+     * @param confClass configuration class.
+     * @return the instance of configuration.
+     * @throws InitializationException
+     */
+    public static <T extends BillingToolConfiguration> T build(String filename, Class<T> confClass) throws InitializationException {
+        try {
+            InputStream is = new FreeMarkerConfig().getInputStream(filename);
+            JsonNode node = getMapper().readTree(new YAMLFactory().createParser(is));
+            return build(node, confClass);
+        } catch (IOException | InitializationException e) {
+            throw new InitializationException("Cannot parse configuration file " + filename + ". " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Build the instance of class {@link BillingToolConfiguration} from YAML file.
+     *
+     * @param node      the content of configuration.
+     * @param confClass configuration class.
+     * @return the instance of configuration.
+     * @throws InitializationException
+     */
+    public static <T extends BillingToolConfiguration> T build(JsonNode node, Class<T> confClass) throws InitializationException {
+        T conf;
+        try {
+            conf = getMapper().readValue(node.toString(), confClass);
+        } catch (Exception e) {
+            throw new InitializationException("Cannot parse json configuration. " + e.getLocalizedMessage(), e);
+        }
+
+        try {
+            LoggingConfigurationFactory logging = conf.getLogging();
+            if (logging != null) {
+                logging.configure();
+            }
+        } catch (Exception e) {
+            throw new InitializationException("Cannot initialize configuration. " + e.getLocalizedMessage(), e);
+        }
+
+        new ConfigurationValidator<T>()
+                .validate(conf);
+
+        return conf;
+    }
+
+    /**
+     * Return the mapper for reading configuration.
+     *
+     * @throws InitializationException
+     */
+    private static ObjectMapper getMapper() throws InitializationException {
+        if (mapper != null) {
+            return mapper;
+        }
+        mapper = new ObjectMapper()
+                .enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+        mapper.registerModule(new GuavaModule());
+        for (Class<?> clazz : BillingUtils.getModuleClassList()) {
+            mapper.registerSubtypes(clazz);
+        }
+
+        return mapper;
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/configuration/ConfigJsonGenerator.java b/services/billing-aws/src/main/java/com/epam/datalab/configuration/ConfigJsonGenerator.java
new file mode 100644
index 0000000..fae1bf6
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/configuration/ConfigJsonGenerator.java
@@ -0,0 +1,103 @@
+/*
+ * 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.datalab.configuration;
+
+import com.epam.datalab.core.BillingUtils;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Generate the json configuration of billing tool.
+ */
+public class ConfigJsonGenerator {
+
+    /**
+     * Buffer for configuration properties.
+     */
+    private Map<String, Map<String, String>[]> config = new HashMap<>();
+
+    /**
+     * Add the properties of module to configuration.
+     *
+     * @param moduleName the name of module.
+     * @param properties the properties: key and value sequence.
+     */
+    private ConfigJsonGenerator withModule(String moduleName, String... properties) {
+        if (properties == null) {
+            config.remove(moduleName);
+            return this;
+        }
+
+        @SuppressWarnings("unchecked")
+        Map<String, String>[] map = new Map[1];
+        map[0] = BillingUtils.stringsToMap(properties);
+        config.put(moduleName, map);
+        return this;
+    }
+
+    /**
+     * Add the properties of input adapter to configuration.
+     *
+     * @param properties the properties: key and value sequence.
+     */
+    public ConfigJsonGenerator withAdapterIn(String... properties) {
+        return withModule("adapterIn", properties);
+    }
+
+    /**
+     * Add the properties of output adapter to configuration.
+     *
+     * @param properties the properties: key and value sequence.
+     */
+    public ConfigJsonGenerator withAdapterOut(String... properties) {
+        return withModule("adapterOut", properties);
+    }
+
+    /**
+     * Add the properties of parser to configuration.
+     *
+     * @param properties the properties: key and value sequence.
+     */
+    public ConfigJsonGenerator withParser(String... properties) {
+        return withModule("parser", properties);
+    }
+
+    /**
+     * Add the properties of filter to configuration.
+     *
+     * @param properties the properties: key and value sequence.
+     */
+    public ConfigJsonGenerator withFilter(String... properties) {
+        return withModule("filter", properties);
+    }
+
+    /**
+     * Build and return json configuration.
+     *
+     * @param properties the properties: key and value sequence.
+     */
+    public JsonNode build() {
+        return new ObjectMapper()
+                .valueToTree(config);
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/configuration/ConfigurationValidator.java b/services/billing-aws/src/main/java/com/epam/datalab/configuration/ConfigurationValidator.java
new file mode 100644
index 0000000..4f8c039
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/configuration/ConfigurationValidator.java
@@ -0,0 +1,71 @@
+/*
+ * 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.datalab.configuration;
+
+import com.epam.datalab.core.BillingUtils;
+import com.epam.datalab.exceptions.InitializationException;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Json properties validator.
+ *
+ * @param <T> Class for validation.
+ */
+public class ConfigurationValidator<T> {
+
+    /**
+     * Error messages.
+     */
+    private static Map<String, String> messages = BillingUtils.stringsToMap(
+            "{javax.validation.constraints.NotNull.message}", "Property \"%s\" may not be null");
+
+    /**
+     * Return the list of error messages.
+     *
+     * @param violation constraint violations.
+     */
+    public String getMessage(ConstraintViolation<T> violation) {
+        return String.format(
+                messages.get(violation.getMessageTemplate()),
+                violation.getPropertyPath(),
+                violation.getInvalidValue());
+    }
+
+    /**
+     * Validate properties in instance and throw exception if it have not valid property.
+     *
+     * @param clazz instance for validation.
+     * @throws InitializationException
+     */
+    public void validate(T clazz) throws InitializationException {
+        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
+        Validator validator = validatorFactory.getValidator();
+        Set<ConstraintViolation<T>> violations = validator.validate(clazz);
+        for (ConstraintViolation<T> violation : violations) {
+            throw new InitializationException(getMessage(violation));
+        }
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/configuration/FreeMarkerConfig.java b/services/billing-aws/src/main/java/com/epam/datalab/configuration/FreeMarkerConfig.java
new file mode 100644
index 0000000..a134f30
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/configuration/FreeMarkerConfig.java
@@ -0,0 +1,84 @@
+/*
+ * 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.datalab.configuration;
+
+import com.google.common.base.Throwables;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Provides Apache FreeMarker the template engine for the billing configuration.
+ */
+public class FreeMarkerConfig {
+
+    /**
+     * Create and return the input stream for the configuration file.
+     *
+     * @param filename the name of configuration file.
+     * @throws IOException
+     */
+    public InputStream getInputStream(final String filename) throws IOException {
+        try {
+            Configuration conf = new Configuration(Configuration.VERSION_2_3_22);
+            Template template = new Template("billing-config", new FileReader(new File(filename)), conf);
+            Map<String, Object> dataModel = getDataModel();
+
+            ByteArrayOutputStream streamBuffer = new ByteArrayOutputStream();
+            template.process(dataModel, new OutputStreamWriter(streamBuffer, StandardCharsets.UTF_8));
+            byte[] buffer = streamBuffer.toByteArray();
+
+            return new ByteArrayInputStream(buffer);
+        } catch (TemplateException e) {
+            throw Throwables.propagate(e);
+        }
+    }
+
+    /**
+     * Create and return JVM and OS properties.
+     */
+    private Map<String, Object> getDataModel() {
+        Map<String, Object> dataModel = new HashMap<>();
+
+        Iterator<Object> sysProps = System.getProperties().keySet().iterator();
+        while (sysProps.hasNext()) {
+            String key = (String) sysProps.next();
+            dataModel.put(key, System.getProperties().getProperty(key));
+        }
+        dataModel.putAll(System.getenv());
+
+        dataModel.put("env", System.getenv());
+        dataModel.put("sys", System.getProperties());
+
+        return dataModel;
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/configuration/LoggingConfigurationFactory.java b/services/billing-aws/src/main/java/com/epam/datalab/configuration/LoggingConfigurationFactory.java
new file mode 100644
index 0000000..e407c14
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/configuration/LoggingConfigurationFactory.java
@@ -0,0 +1,170 @@
+/*
+ * 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.datalab.configuration;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.logging.AppenderBase;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.slf4j.LoggerFactory;
+
+import javax.validation.Valid;
+
+/**
+ * Configuration and factory for logging.
+ */
+public class LoggingConfigurationFactory {
+
+    /**
+     * Default logging level for all appenders.
+     */
+    @Valid
+    @JsonProperty
+    private Level level = Level.INFO;
+
+    /**
+     * List of logging levels for appenders.
+     */
+    @JsonIgnore
+    private ImmutableMap<String, Level> loggers = ImmutableMap.of();
+
+    /**
+     * List of logging appenders.
+     */
+    @Valid
+    @JsonProperty
+    private ImmutableList<AppenderBase> appenders = ImmutableList.of();
+
+
+    /**
+     * Return the default logging level for all appenders.
+     */
+    public Level getLevel() {
+        return level;
+    }
+
+    /**
+     * Set the default logging level for all appenders.
+     */
+    public void setLevel(String level) throws InitializationException {
+        this.level = toLevel(level);
+    }
+
+    /**
+     * Return the list of logging levels for appenders.
+     */
+    public ImmutableMap<String, Level> getLoggers() {
+        return loggers;
+    }
+
+    /**
+     * Set the list of logging levels for appenders.
+     */
+    @JsonProperty
+    public void setLoggers(ImmutableMap<String, JsonNode> loggers) throws InitializationException {
+        ImmutableMap.Builder<String, Level> levels = new ImmutableMap.Builder<>();
+        for (String key : loggers.keySet()) {
+            JsonNode node = loggers.get(key);
+            levels.put(key, toLevel(node.asText()));
+        }
+        this.loggers = levels.build();
+    }
+
+    /**
+     * Return the list of logging appenders.
+     */
+    public ImmutableList<AppenderBase> getAppenders() {
+        return appenders;
+    }
+
+    /**
+     * Set the list of logging appenders.
+     */
+    public void setAppenders(ImmutableList<AppenderBase> appenders) {
+        this.appenders = appenders;
+    }
+
+
+    /**
+     * Translate the name of logging level to {@link Level}.
+     *
+     * @param level the name of logging level.
+     * @return logging level.
+     * @throws InitializationException if given unknown logging level name.
+     */
+    private Level toLevel(String level) throws InitializationException {
+        Level l = Level.toLevel(level, null);
+        if (l == null) {
+            throw new InitializationException("Unknown logging level: " + level);
+        }
+        return l;
+    }
+
+    /**
+     * Configure logging appenders.
+     *
+     * @throws InitializationException
+     */
+    public void configure() throws InitializationException {
+        if (appenders == null) {
+            throw new InitializationException("Configuration property logging.appenders cannot be null.");
+        }
+        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+        context.reset();
+
+        for (AppenderBase appender : appenders) {
+            appender.configure(context);
+        }
+
+        Logger logger = context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
+        logger.setLevel(level);
+        for (String name : loggers.keySet()) {
+            logger = context.getLogger(name);
+            logger.setLevel(loggers.get(name));
+        }
+    }
+
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @param self the object to generate the string for (typically this), used only for its class name.
+     */
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("level", level)
+                .add("loggers", loggers)
+                .add("appenders", appenders);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .toString();
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/controller/BillingController.java b/services/billing-aws/src/main/java/com/epam/datalab/controller/BillingController.java
new file mode 100644
index 0000000..d28d9f4
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/controller/BillingController.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.controller;
+
+import com.epam.datalab.BillingService;
+import com.epam.datalab.dto.billing.BillingData;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+public class BillingController {
+
+    private final BillingService billingService;
+
+    public BillingController(BillingService billingService) {
+        this.billingService = billingService;
+    }
+
+    @GetMapping
+    public ResponseEntity<List<BillingData>> getBilling() {
+        return new ResponseEntity<>(billingService.getBillingData(), HttpStatus.OK);
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/AdapterBase.java b/services/billing-aws/src/main/java/com/epam/datalab/core/AdapterBase.java
new file mode 100644
index 0000000..9ceea05
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/AdapterBase.java
@@ -0,0 +1,173 @@
+/*
+ * 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.datalab.core;
+
+import com.epam.datalab.exceptions.AdapterException;
+import com.epam.datalab.model.aws.ReportLine;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.bson.Document;
+
+import java.util.List;
+
+/**
+ * Abstract module for read/write adapter.
+ * See description of {@link ModuleBase} how to create your own adapter.
+ */
+public abstract class AdapterBase extends ModuleBase {
+    public enum Mode {READ, WRITE}
+
+    ;
+
+    /**
+     * Flag the header of common format should be written to target.
+     */
+    @JsonProperty
+    private boolean writeHeader = true;
+
+
+    /**
+     * The mode of adapter read or write.
+     */
+    @JsonIgnore
+    private Mode mode;
+
+
+    /**
+     * Default constructor for deserialization.
+     */
+    public AdapterBase() {
+    }
+
+    /**
+     * Instantiate adapter for reading or writing.
+     *
+     * @param mode the mode of adapter.
+     */
+    public AdapterBase(Mode mode) {
+        this.mode = mode;
+    }
+
+
+    /**
+     * Return <b>true</b> if the header of common format should be written to target.
+     */
+    public boolean isWriteHeader() {
+        return writeHeader;
+    }
+
+    /**
+     * Set flag the header of common format should be written to target.
+     */
+    public void setWriteHeader(boolean writeHeader) {
+        this.writeHeader = writeHeader;
+    }
+
+
+    /**
+     * Return the mode of adapter read or write.
+     */
+    public Mode getMode() {
+        return mode;
+    }
+
+    /**
+     * Set the mode of adapter read or write.
+     */
+    public void setMode(Mode mode) {
+        this.mode = mode;
+    }
+
+
+    /**
+     * Open connection.
+     *
+     * @throws AdapterException if cannot open connection.
+     */
+    public abstract void open() throws AdapterException;
+
+    /**
+     * Return <b>true</b> if adapter has the multiply entries of data.
+     */
+    public boolean hasMultyEntry() {
+        return false;
+    }
+
+    /**
+     * Return <b>true</b> if current entry has the data.
+     */
+    public boolean hasEntryData() {
+        return true;
+    }
+
+    /**
+     * Open next entry if exists and return <b>true</b> otherwise return <b>false</b>.
+     *
+     * @throws AdapterException if cannot open entry.
+     */
+    public boolean openNextEntry() throws AdapterException {
+        return false;
+    }
+
+    /**
+     * Close connection.
+     *
+     * @throws AdapterException if cannot close connection.
+     */
+    public abstract void close() throws AdapterException;
+
+    /**
+     * Return the current processed entry name.
+     */
+    public abstract String getEntryName();
+
+    /**
+     * Read the line of data from adapter and return it.
+     *
+     * @throws AdapterException
+     */
+    public abstract String readLine() throws AdapterException;
+
+    /**
+     * Write the header of data to adapter.
+     *
+     * @param header the header of common format.
+     * @throws AdapterException
+     */
+    public abstract void writeHeader(List<String> header) throws AdapterException;
+
+    /**
+     * Write the row of data to adapter.
+     *
+     * @param row the row of common format.
+     * @return
+     * @throws AdapterException
+     */
+    public abstract Document writeRow(ReportLine row) throws AdapterException;
+
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("mode", mode)
+                .add("writeHeader", isWriteHeader());
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/BillingUtils.java b/services/billing-aws/src/main/java/com/epam/datalab/core/BillingUtils.java
new file mode 100644
index 0000000..65ec1b5
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/BillingUtils.java
@@ -0,0 +1,144 @@
+/*
+ * 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.datalab.core;
+
+import com.epam.datalab.configuration.BillingToolConfigurationFactory;
+import com.epam.datalab.core.parser.ParserBase;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.logging.AppenderBase;
+import com.google.common.io.Resources;
+
+import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Billing toll utilities.
+ */
+public class BillingUtils {
+
+    /**
+     * Name of resource with the names of module classes.
+     */
+    private static final String RESOURCE_MODULE_NAMES = "/" + BillingToolConfigurationFactory.class.getName();
+
+    private BillingUtils() {
+    }
+
+    /**
+     * Create and return map from given key/values.
+     *
+     * @param keyValues the key/value pairs.
+     */
+    public static Map<String, String> stringsToMap(String... keyValues) {
+        Map<String, String> map = new HashMap<>();
+        if (keyValues == null) {
+            return map;
+        }
+        if (keyValues.length % 2 != 0) {
+            throw new IllegalArgumentException("Missing key or value in arguments");
+        }
+
+        for (int i = 1; i < keyValues.length; i += 2) {
+            map.put(keyValues[i - 1], keyValues[i]);
+        }
+        return map;
+    }
+
+    /**
+     * Read and return content as string list from resource.
+     *
+     * @param resourceName the name of resource.
+     * @return list of strings.
+     * @throws InitializationException
+     */
+    public static List<String> getResourceAsList(String resourceName) throws InitializationException {
+        try {
+            URL url = BillingToolConfigurationFactory.class.getResource(resourceName);
+            if (url == null) {
+                throw new InitializationException("Resource " + resourceName + " not found");
+            }
+            return Resources.readLines(url, Charset.forName("utf-8"));
+        } catch (IllegalArgumentException | IOException e) {
+            throw new InitializationException("Cannot read resource " + resourceName + ": " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Return the list of billing tool modules.
+     *
+     * @throws InitializationException
+     */
+    public static List<Class<?>> getModuleClassList() throws InitializationException {
+        List<String> modules = getResourceAsList(RESOURCE_MODULE_NAMES);
+        List<Class<?>> classes = new ArrayList<>();
+
+        for (String className : modules) {
+            try {
+                classes.add(Class.forName(className));
+            } catch (ClassNotFoundException e) {
+                throw new InitializationException("Cannot add the sub type " + className +
+                        " from resource " + RESOURCE_MODULE_NAMES + ": " + e.getLocalizedMessage(), e);
+            }
+        }
+        return classes;
+    }
+
+    /**
+     * Check for child class is belong to parent by hierarchy.
+     *
+     * @param child  the child class for check.
+     * @param parent the parent class from hierarchy.
+     */
+    public static boolean classChildOf(Class<?> child, Class<?> parent) {
+        return child != null && parent != null && parent.isAssignableFrom(child);
+    }
+
+    /**
+     * Return the type of module if class is module otherwise <b>null</b>.
+     *
+     * @param moduleClass the class.
+     */
+    public static ModuleType getModuleType(Class<?> moduleClass) {
+        if (classChildOf(moduleClass, AdapterBase.class)) {
+            return ModuleType.ADAPTER;
+        } else if (classChildOf(moduleClass, FilterBase.class)) {
+            return ModuleType.FILTER;
+        } else if (classChildOf(moduleClass, ParserBase.class)) {
+            return ModuleType.PARSER;
+        } else if (classChildOf(moduleClass, AppenderBase.class)) {
+            return ModuleType.LOGAPPENDER;
+        }
+        return null;
+    }
+
+    /**
+     * Return the name of user without domain.
+     *
+     * @param value the value.
+     */
+    public static String getSimpleUserName(String username) {
+        return (username == null ? null : username.replaceAll("@.*", ""));
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/DBAdapterBase.java b/services/billing-aws/src/main/java/com/epam/datalab/core/DBAdapterBase.java
new file mode 100644
index 0000000..cda3da0
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/DBAdapterBase.java
@@ -0,0 +1,163 @@
+/*
+ * 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.datalab.core;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+/**
+ * The abstract adapter for database.
+ * See description of {@link ModuleBase} how to create your own adapter.
+ */
+public abstract class DBAdapterBase extends AdapterBase {
+
+    /**
+     * The host name.
+     */
+    @JsonProperty
+    private String host;
+
+    /**
+     * The port.
+     */
+    @JsonProperty
+    private int port;
+
+    /**
+     * The name of database.
+     */
+    @JsonProperty
+    private String database;
+
+    /**
+     * The name of user.
+     */
+    @JsonProperty
+    private String username;
+
+    /**
+     * The password.
+     */
+    @JsonProperty
+    private String password;
+
+
+    /**
+     * Default constructor for deserialization.
+     */
+    public DBAdapterBase() {
+    }
+
+    /**
+     * Instantiate adapter for reading or writing.
+     *
+     * @param mode the mode of adapter.
+     */
+    public DBAdapterBase(Mode mode) {
+        super(mode);
+    }
+
+
+    @Override
+    public boolean isWriteHeader() {
+        return false;
+    }
+
+    /**
+     * Return the host name.
+     */
+    public String getHost() {
+        return host;
+    }
+
+    /**
+     * Set the host name.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    /**
+     * Return the port.
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * Set the port.
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    /**
+     * Return the name of database.
+     */
+    public String getDatabase() {
+        return database;
+    }
+
+    /**
+     * Set the name of database.
+     */
+    public void setDatabase(String database) {
+        this.database = database;
+    }
+
+    /**
+     * Return the name of user.
+     */
+    public String getUsername() {
+        return username;
+    }
+
+    /**
+     * Set the name of user.
+     */
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    /**
+     * Return the password.
+     */
+    public String getPassword() {
+        return password;
+    }
+
+    /**
+     * Set the password.
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("host", host)
+                .add("port", port)
+                .add("database", database)
+                .add("username", username)
+                .add("password", "***");
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/FilterBase.java b/services/billing-aws/src/main/java/com/epam/datalab/core/FilterBase.java
new file mode 100644
index 0000000..4e17514
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/FilterBase.java
@@ -0,0 +1,95 @@
+/*
+ * 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.datalab.core;
+
+import com.epam.datalab.core.parser.ParserBase;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.exceptions.ParseException;
+import com.epam.datalab.model.aws.ReportLine;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.List;
+
+/**
+ * Abstract module of filtering.
+ * See description of {@link ModuleBase} how to create your own filter.
+ */
+public abstract class FilterBase extends ModuleBase {
+
+    /**
+     * Parser.
+     */
+    private ParserBase parser;
+
+    /**
+     * Return parser.
+     */
+    public ParserBase getParser() {
+        return parser;
+    }
+
+    /**
+     * Set parser.
+     */
+    public void setParser(ParserBase parser) {
+        this.parser = parser;
+    }
+
+
+    /**
+     * Initialize the filter.
+     *
+     * @throws InitializationException
+     */
+    public abstract void initialize() throws InitializationException;
+
+    /**
+     * Return the line for parsing if line is accepted and may be parsed,
+     * otherwise return <b>null</b>.
+     *
+     * @param line the source line.
+     * @throws ParseException
+     */
+    public abstract String canParse(String line) throws ParseException;
+
+    /**
+     * Return the list of values for transformation if value is accepted and may be transformed,
+     * otherwise return <b>null</b>.
+     *
+     * @param row the list of values.
+     * @throws ParseException
+     */
+    public abstract List<String> canTransform(List<String> row) throws ParseException;
+
+    /**
+     * Return the row of billing report if row is accepted and may be written to target,
+     * otherwise return <b>null</b>.
+     *
+     * @param row the report line.
+     * @throws ParseException
+     */
+    public abstract ReportLine canAccept(ReportLine row) throws ParseException;
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("parser", (parser == null ? null : parser.getType()));
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/ModuleBase.java b/services/billing-aws/src/main/java/com/epam/datalab/core/ModuleBase.java
new file mode 100644
index 0000000..acb26a3
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/ModuleBase.java
@@ -0,0 +1,84 @@
+/*
+ * 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.datalab.core;
+
+import com.epam.datalab.core.parser.ParserBase;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+/**
+ * Abstract class for modules: adapter, filter, parser.<br>
+ * To create your adapter:<br>
+ * 1. Create a class which extends one of {@link AdapterBase}, {@link FilterBase} or {@link ParserBase} classes.<br>
+ * 2. Annotate it with {@link JsonTypeName} annotation and give it a unique type name for this type of modules.<br>
+ * 3. Add full the name of your class to main/resources/com.epam.datalab.configuration.BillingToolConfigurationFactory file.
+ * 4. Annotate it with {@link JsonClassDescription] annotation and describe all properties of module.
+ */
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
+public abstract class ModuleBase {
+
+    /**
+     * Working data of module.
+     */
+    @JsonIgnore
+    private ModuleData moduleData;
+
+    /**
+     * Return the name of type for appender.
+     */
+    @JsonIgnore
+    public String getType() {
+        Class<? extends ModuleBase> clazz = this.getClass();
+        return (clazz.isAnnotationPresent(JsonTypeName.class) ?
+                clazz.getAnnotation(JsonTypeName.class).value() : clazz.getName());
+    }
+
+    /**
+     * Return the working data of module.
+     */
+    public ModuleData getModuleData() {
+        return moduleData;
+    }
+
+    /**
+     * Set the working data of module.
+     */
+    public void setModuleData(ModuleData moduleData) {
+        this.moduleData = moduleData;
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @param self the object to generate the string for (typically this), used only for its class name.
+     */
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("type", getType());
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/ModuleData.java b/services/billing-aws/src/main/java/com/epam/datalab/core/ModuleData.java
new file mode 100644
index 0000000..41e1bdd
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/ModuleData.java
@@ -0,0 +1,182 @@
+/*
+ * 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.datalab.core;
+
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.mongo.MongoConstants;
+import com.epam.datalab.mongo.MongoDbConnection;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.mongodb.client.FindIterable;
+import com.mongodb.client.model.UpdateOptions;
+import org.apache.commons.lang3.StringUtils;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.gte;
+import static com.mongodb.client.model.Filters.or;
+import static com.mongodb.client.model.Filters.regex;
+
+/**
+ * Provides loading and storing the working data of modules.
+ */
+public class ModuleData {
+
+    public static final String ENTRIES_FIELD = "entries";
+    private static final String ID_FIELD = "_id";
+    private static final String MODIFICATION_DATE = "lastModificationDate";
+    /**
+     * Date formatter.
+     */
+    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
+    private final MongoDbConnection connection;
+
+    private String id;
+    private Date modificationDate;
+
+    /**
+     * Entries of data.
+     */
+    private Map<String, String> entries = new HashMap<>();
+
+    /**
+     * Flag modification of entries.
+     */
+    private boolean modified;
+
+    /**
+     * Instantiate module data.
+     *
+     * @param connection the name of data file.
+     * @throws InitializationException
+     */
+    public ModuleData(MongoDbConnection connection) {
+        this.connection = connection;
+    }
+
+    /**
+     * Return <b>true</b> if any entries was modify.
+     */
+    public boolean isModified() {
+        return modified;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setModificationDate(Date modificationDate) {
+        this.modificationDate = modificationDate;
+    }
+
+    /**
+     * Return the value for given key or <b>null</b> if value not found.
+     *
+     * @param key the key of entry.
+     */
+    public String getString(String key) {
+        return entries.get(key);
+    }
+
+    /**
+     * Return the date value for given key or <b>null</b> if value not found.
+     *
+     * @param key the key of entry.
+     * @throws ParseException
+     */
+    public Date getDate(String key) throws ParseException {
+        String value = entries.get(key);
+        return (value == null ? null : dateFormat.parse(value));
+    }
+
+    /**
+     * Set value for given key or delete entry if the value is <b>null</b>.
+     *
+     * @param key   the key of entry.
+     * @param value the value.
+     */
+    public void set(String key, String value) {
+        if (StringUtils.equals(entries.get(key), value)) {
+            return;
+        } else if (value == null) {
+            entries.remove(key);
+        } else {
+            entries.put(key, value);
+        }
+        modified = true;
+    }
+
+    /**
+     * Set value for given key or delete entry if the value is <b>null</b>.
+     *
+     * @param key   the key of entry.
+     * @param value the date.
+     */
+    public void set(String key, Date value) {
+        set(key, dateFormat.format(value));
+    }
+
+    public void store() {
+        final Document document = new Document().append(ID_FIELD, id).append(MODIFICATION_DATE, modificationDate).append(ENTRIES_FIELD, entries);
+        connection.getCollection(MongoConstants.BILLING_DATA_COLLECTION)
+                .updateOne(eq(ID_FIELD, id), new Document("$set", document), new UpdateOptions().upsert(true));
+        modified = false;
+    }
+
+    public boolean wasProcessed(String fileName, Date modificationDate, String datePrefix) {
+        final Bson filePerBillingPeriodCondition = and(regex(ID_FIELD, "^" + datePrefix), gte(MODIFICATION_DATE,
+                modificationDate));
+        final Bson fileWithExactNameCondition = and(eq(ID_FIELD, fileName), gte(MODIFICATION_DATE, modificationDate));
+        final FindIterable<Document> documents = connection.getCollection(MongoConstants.BILLING_DATA_COLLECTION)
+                .find(or(fileWithExactNameCondition, filePerBillingPeriodCondition))
+                .limit(1);
+        return documents.iterator().hasNext();
+    }
+
+    public void closeMongoConnection() throws IOException {
+        connection.close();
+    }
+
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @param self the object to generate the string for (typically this), used only for its class name.
+     */
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .addValue(entries);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .toString();
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/ModuleType.java b/services/billing-aws/src/main/java/com/epam/datalab/core/ModuleType.java
new file mode 100644
index 0000000..1b30446
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/ModuleType.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.core;
+
+/**
+ * The type of billing modules: adapter, filter, parser or log appender.
+ */
+public enum ModuleType {
+    ADAPTER,
+    FILTER,
+    PARSER,
+    LOGAPPENDER;
+
+    @Override
+    public String toString() {
+        return super.toString().toLowerCase();
+    }
+
+    public static ModuleType of(String string) {
+        if (string != null) {
+            for (ModuleType value : ModuleType.values()) {
+                if (string.equalsIgnoreCase(value.toString())) {
+                    return value;
+                }
+            }
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/aggregate/AggregateGranularity.java b/services/billing-aws/src/main/java/com/epam/datalab/core/aggregate/AggregateGranularity.java
new file mode 100644
index 0000000..20617d2
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/aggregate/AggregateGranularity.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.core.aggregate;
+
+/**
+ * Aggregate granularity for aggregation.
+ */
+public enum AggregateGranularity {
+    NONE,
+    DAY,
+    MONTH;
+
+    @Override
+    public String toString() {
+        return super.toString().toLowerCase();
+    }
+
+    public static AggregateGranularity of(String string) {
+        if (string != null) {
+            for (AggregateGranularity value : AggregateGranularity.values()) {
+                if (string.equalsIgnoreCase(value.toString())) {
+                    return value;
+                }
+            }
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/aggregate/DataAggregator.java b/services/billing-aws/src/main/java/com/epam/datalab/core/aggregate/DataAggregator.java
new file mode 100644
index 0000000..0800182
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/aggregate/DataAggregator.java
@@ -0,0 +1,172 @@
+/*
+ * 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.datalab.core.aggregate;
+
+import com.epam.datalab.model.aws.ReportLine;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Vector;
+
+/**
+ * Aggregate billing report and summarizes column usage and cost.
+ */
+public class DataAggregator {
+    /**
+     * List of the report lines.
+     */
+    private final Vector<ReportLine> reportLines = new Vector<>(1000);
+
+    /**
+     * Comparator for aggregation.
+     */
+    private final Comparator<ReportLine> aggComparator = new AggComparator();
+
+    /**
+     * Granularity for aggregation.
+     */
+    private AggregateGranularity granularity;
+
+    /**
+     * Length of date for truncate.
+     */
+    private int truncateDateLength;
+
+
+    public DataAggregator(AggregateGranularity granularity) {
+        switch (granularity) {
+            case DAY:
+                truncateDateLength = 10;
+                break;
+            case MONTH:
+                truncateDateLength = 7;
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid value of granularity argument: expected DAY or MONTH, " +
+                        "actual is " + granularity);
+        }
+        this.granularity = granularity;
+    }
+
+    /**
+     * Return granularity for aggregation.
+     */
+    public AggregateGranularity getGranularity() {
+        return granularity;
+    }
+
+    /**
+     * Appends the report line to the list and returns it.
+     *
+     * @param row the line of report.
+     * @return Instance of the aggregated report line.
+     */
+    public ReportLine append(ReportLine row) {
+        synchronized (this) {
+            String usageInterval = truncDate(row.getUsageDate());
+            row.setUsageDate(usageInterval);
+            int index = Collections.binarySearch(reportLines, row, aggComparator);
+            if (index < 0) {
+                index = -index;
+                if (index > reportLines.size()) {
+                    reportLines.add(row);
+                } else {
+                    reportLines.add(index - 1, row);
+                }
+            } else {
+                ReportLine found = reportLines.get(index);
+                found.setUsage(found.getUsage() + row.getUsage());
+                found.setCost(found.getCost() + row.getCost());
+                return found;
+            }
+        }
+
+        return row;
+    }
+
+    /**
+     * Truncate given date for aggregates.
+     *
+     * @param date the date.
+     * @return truncated date.
+     */
+    private String truncDate(String date) {
+        if (date == null || date.length() <= truncateDateLength) {
+            return date;
+        }
+        return date.substring(0, truncateDateLength);
+    }
+
+    /**
+     * Returns the number of the report lines in list.
+     */
+    public int size() {
+        return reportLines.size();
+    }
+
+    /**
+     * Returns the report line.
+     *
+     * @param index index of the report line.
+     */
+    public ReportLine get(int index) {
+        return reportLines.get(index);
+    }
+
+    /**
+     * Removes all of the elements from list.
+     */
+    public void clear() {
+        reportLines.clear();
+    }
+
+    /**
+     * Comparator for aggregation.
+     */
+    private class AggComparator implements Comparator<ReportLine> {
+        @Override
+        public int compare(ReportLine o1, ReportLine o2) {
+            if (o1 == null) {
+                return (o2 == null ? 0 : -1);
+            } else if (o2 == null) {
+                return 1;
+            }
+
+            int result = StringUtils.compare(o1.getResourceId(), o2.getResourceId());
+            if (result == 0) {
+                result = StringUtils.compare(o1.getUsageType(), o2.getUsageType());
+                if (result == 0) {
+                    result = StringUtils.compare(o1.getUsageDate(), o2.getUsageDate());
+                    if (result == 0) {
+                        result = StringUtils.compare(o1.getProduct(), o2.getProduct());
+                        if (result == 0) {
+                            result = StringUtils.compare(o1.getUser(), o2.getUser());
+                            if (result == 0) {
+                                return StringUtils.compare(o1.getDatalabId(), o2.getDatalabId());
+                            }
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/aggregate/UsageDataList.java b/services/billing-aws/src/main/java/com/epam/datalab/core/aggregate/UsageDataList.java
new file mode 100644
index 0000000..f45381c
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/aggregate/UsageDataList.java
@@ -0,0 +1,87 @@
+/*
+ * 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.datalab.core.aggregate;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * List of usage dates the billing report data.
+ */
+public class UsageDataList implements Iterable<String> {
+    /**
+     * List of dates.
+     */
+    private final Map<String, Boolean> map = new HashMap<>();
+
+    /**
+     * Appends the date to the list and returns it.
+     *
+     * @param usageDate the date of data.
+     * @return Instance of the range.
+     */
+    public void append(String usageDate) {
+        synchronized (this) {
+            if (!map.containsKey(usageDate)) {
+                map.put(usageDate, false);
+            }
+        }
+    }
+
+    /**
+     * Returns the number of the range in list.
+     */
+    public int size() {
+        return map.size();
+    }
+
+    /**
+     * Returns the value for date.
+     *
+     * @param usageDate the date.
+     */
+    public Boolean get(String usageDate) {
+        return map.get(usageDate);
+    }
+
+    /**
+     * Set the value of usageDate.
+     *
+     * @param usageDate the date.
+     */
+    public void set(String usageDate, boolean value) {
+        if (map.containsKey(usageDate)) {
+            map.put(usageDate, value);
+        }
+    }
+
+    /**
+     * Removes all of the elements from list.
+     */
+    public void clear() {
+        map.clear();
+    }
+
+    @Override
+    public Iterator<String> iterator() {
+        return map.keySet().iterator();
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ColumnInfo.java b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ColumnInfo.java
new file mode 100644
index 0000000..ee5aceb
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ColumnInfo.java
@@ -0,0 +1,59 @@
+/*
+ * 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.datalab.core.parser;
+
+/**
+ * Describe the info of column mapping: source to target.
+ */
+public class ColumnInfo {
+
+    /**
+     * The target column name.
+     */
+    public final String targetName;
+
+    /**
+     * The source column name.
+     */
+    public final String sourceName;
+
+    /**
+     * The source column index.
+     */
+    public final int sourceIndex;
+
+    /**
+     * Instantiate the info of column mapping.
+     *
+     * @param targetName  the target column name.
+     * @param sourceName  the source column name.
+     * @param sourceIndex the source column index.
+     */
+    public ColumnInfo(String targetName, String sourceName, int sourceIndex) {
+        this.targetName = targetName;
+        this.sourceName = sourceName;
+        this.sourceIndex = sourceIndex;
+    }
+
+    @Override
+    public String toString() {
+        return targetName + "=" + (sourceName == null ? "" : sourceName + "[" + sourceIndex + "]");
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ColumnMeta.java b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ColumnMeta.java
new file mode 100644
index 0000000..63172bd
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ColumnMeta.java
@@ -0,0 +1,318 @@
+/*
+ * 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.datalab.core.parser;
+
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.model.aws.ReportLine;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides column meta information.
+ */
+public class ColumnMeta {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ColumnMeta.class);
+
+    /**
+     * Character for separate the tag values and column names.
+     */
+    public static final char TAG_SEPARATOR = ',';
+    /**
+     * Character for separate the column mapping.
+     */
+    public static final char MAPPING_COLUMN_SEPARATOR = ';';
+
+    /**
+     * The column names for common format.
+     */
+    static final String[] COLUMN_NAMES = {
+            ReportLine.FIELD_DATALAB_ID,
+            ReportLine.FIELD_USER_ID,
+            ReportLine.FIELD_USAGE_DATE,
+            ReportLine.FIELD_PRODUCT,
+            ReportLine.FIELD_USAGE_TYPE,
+            ReportLine.FIELD_USAGE,
+            ReportLine.FIELD_COST,
+            ReportLine.FIELD_CURRENCY_CODE,
+            ReportLine.FIELD_RESOURCE_ID,
+            ReportLine.FIELD_TAGS
+    };
+
+    /**
+     * The index of the first column for tags.
+     */
+    public static final int TAG_COLUMN_INDEX = COLUMN_NAMES.length - 1;
+
+    /**
+     * The list of target column names.
+     */
+    private List<String> targetColumnNames;
+
+    /**
+     * The list of source column names.
+     */
+    private final List<String> sourceColumnNames;
+
+    /**
+     * The list of column mapping: source to target.
+     */
+    private List<ColumnInfo> columnMapping;
+
+
+    /**
+     * Instantiate the common format parser. <b>columnMappingString</b> is semicolon separated
+     * string with key=value as target=source columns name or indexes of source column. For example,<br>
+     * "accountId=PayerAccountId;usageIntervalStart=UsageStartDate;usageIntervalEnd=UsageEndDate; ...
+     * ;tags=user:tag1,user:tag2,user:tagN".
+     *
+     * @param columnMappingString column mapping: source to target. if <b>null</b>
+     *                            the source data will be converted without mapping.
+     * @param sourceColumnNames   the source column names.
+     * @throws InitializationException
+     */
+    public ColumnMeta(String columnMappingString, List<String> sourceColumnNames) throws InitializationException {
+        this.sourceColumnNames = sourceColumnNames;
+        if (columnMappingString != null) {
+            try {
+                setColumnMapping(columnMappingString, sourceColumnNames);
+            } catch (Exception e) {
+                throw new InitializationException("Column mapping error. " + e.getLocalizedMessage(), e);
+            }
+        }
+    }
+
+
+    /**
+     * Return the list of target column names.
+     */
+    public List<String> getTargetColumnNames() {
+        return targetColumnNames;
+    }
+
+    /**
+     * Return the list of source column names.
+     */
+    public List<String> getSourceColumnNames() {
+        return sourceColumnNames;
+    }
+
+    /**
+     * Return the list of column mapping: source to target.
+     */
+    public List<ColumnInfo> getColumnMapping() {
+        return columnMapping;
+    }
+
+
+    /**
+     * Return the index of column in the list <b>columnNames</b> or throw exception {@link InitializationException}
+     *
+     * @param columnName  the name of column.
+     * @param columnNames the list of column names.
+     * @return the index of column.
+     * @throws InitializationException if column not found in the list of columns.
+     */
+    public static int getColumnIndexByName(String columnName, List<String> columnNames) throws
+            InitializationException {
+        for (int i = 0; i < columnNames.size(); i++) {
+            if (columnName.equals(columnNames.get(i))) {
+                return i;
+            }
+        }
+        throw new InitializationException("Column index not detected for column \"" + columnName + "\"");
+    }
+
+    /**
+     * Return the index of column in the list <b>columnNames</b> or throw exception {@link InitializationException}.
+     * columnName may be present as column index. For example like this "$2" for second column.
+     *
+     * @param columnName  the name of column or index.
+     * @param columnNames the list of column names.
+     * @return the index of column.
+     * @throws InitializationException if column not found in the list of columns.
+     */
+    private static int getColumnIndex(String columnName, List<String> columnNames) throws InitializationException {
+        if (columnName.startsWith("$")) {
+            try {
+                return Integer.parseInt(columnName.substring(1)) - 1;
+            } catch (NumberFormatException e) {
+                // Not a column index but column name
+            }
+        }
+        if (columnNames == null) {
+            throw new InitializationException("Invalid column index \"" + columnName + "\"");
+        }
+        return getColumnIndexByName(columnName, columnNames);
+    }
+
+    /**
+     * Return the index of column in the list <b>columnNames</b> or throw exception {@link InitializationException}.
+     * columnName may be present as column index. For example like this "$2" for second column.
+     *
+     * @param columnName the name of column or index.
+     * @return the index of column.
+     * @throws InitializationException if column not found in the list of columns.
+     */
+    private static int getColumnIndex(String columnName) throws InitializationException {
+        ArrayList<String> list = new ArrayList<>(COLUMN_NAMES.length);
+        for (String s : COLUMN_NAMES) {
+            list.add(s);
+        }
+        return getColumnIndexByName(columnName, list);
+    }
+
+    /**
+     * Create map of target and source columns for column mapping. Key of map is target column, the value
+     * is source column. <b>columnMappingString</b> is semicolon separated string with key=value as
+     * target=source columns name or indexes of source column. For example,<br>
+     * "accountId=PayerAccountId;usageIntervalStart=UsageStartDate;usageIntervalEnd=UsageEndDate; ...
+     * ;tags=user:tag1,user:tag2,user:tagN".
+     *
+     * @param columnMappingString column mapping: source to target.
+     * @param sourceColumnNames
+     * @return Map of target and source columns for column mapping.
+     * @throws InitializationException
+     */
+    private Map<String, String> getSourceToTarget(String columnMappingString, List<String> sourceColumnNames) throws
+            InitializationException {
+        String[] entries = StringUtils.split(columnMappingString, MAPPING_COLUMN_SEPARATOR);
+        Map<String, String> sourceToTarget = new HashMap<>();
+
+        for (String entry : entries) {
+            if (entry.trim().isEmpty() || !entry.contains("=")) {
+                throw new InitializationException("Invalid the entry \"" + entry + "\"in column mapping");
+            }
+            String[] pair = StringUtils.split(entry, '=');
+            if (pair.length != 2) {
+                throw new InitializationException("Invalid the entry \"" + entry + "\"in column mapping");
+            }
+
+            pair[0] = pair[0].trim();
+            pair[1] = pair[1].trim();
+
+            try {
+                int index = getColumnIndex(pair[0]);
+                pair[0] = COLUMN_NAMES[index];
+            } catch (InitializationException e) {
+                throw new InitializationException("Unkown target column \"" + pair[0] + "\".", e);
+            }
+
+            try {
+                if (!pair[0].equals(ReportLine.FIELD_TAGS)) {
+                    int index = getColumnIndex(pair[1], sourceColumnNames);
+                    if (sourceColumnNames != null) {
+                        pair[1] = sourceColumnNames.get(index);
+                    }
+                }
+            } catch (InitializationException e) {
+                if (sourceColumnNames == null) {
+                    throw new InitializationException("Invalid column index \"" + pair[1] + "\" or column header not " +
+                            "defined");
+                }
+                throw new InitializationException("Unkown source column \"" + pair[1] + "\".", e);
+            }
+            sourceToTarget.put(pair[0], pair[1]);
+        }
+
+        return sourceToTarget;
+    }
+
+    /**
+     * Initialize and set column mapping. <b>columnMappingString</b> is semicolon separated string with key=value as
+     * target=source columns name or indexes of source column. For example,<br>
+     * "accountId=PayerAccountId;usageIntervalStart=UsageStartDate;usageIntervalEnd=UsageEndDate; ...
+     * ;tags=user:tag1,user:tag2,user:tagN".
+     *
+     * @param columnMappingString column mapping: source to target. if <b>null</b>
+     *                            the source data will be converted without mapping.
+     * @param sourceColumnNames   the list of source column names.
+     * @throws InitializationException
+     */
+    private void setColumnMapping(String columnMappingString, List<String> sourceColumnNames) throws
+            InitializationException {
+        if (columnMappingString == null) {
+            throw new InitializationException("Mapping not defined.");
+        }
+
+        Map<String, String> sourceToTarget = getSourceToTarget(columnMappingString, sourceColumnNames);
+        String tags = sourceToTarget.get(ReportLine.FIELD_TAGS);
+        List<String> tagColumns = (tags == null ? null :
+                Arrays.asList(StringUtils.split(tags, TAG_SEPARATOR)));
+
+        LOGGER.info("Mapping columns [target=source:name[index]]:");
+        int columnCount = COLUMN_NAMES.length - 1;
+        int tagCount = (tagColumns == null ? 0 : tagColumns.size());
+        columnMapping = new ArrayList<>(columnCount + tagCount);
+        targetColumnNames = new ArrayList<>(columnCount + tagCount);
+
+        for (int i = 0; i < columnCount; i++) {
+            String sourceName = sourceToTarget.get(COLUMN_NAMES[i]);
+            ColumnInfo columnInfo = new ColumnInfo(
+                    COLUMN_NAMES[i],
+                    sourceName,
+                    (sourceName == null ? -1 : getColumnIndex(sourceName, sourceColumnNames)));
+            columnMapping.add(columnInfo);
+            targetColumnNames.add(COLUMN_NAMES[i]);
+            LOGGER.info("  " + columnInfo.toString());
+        }
+
+        for (int i = 0; i < tagCount; i++) {
+            String sourceName = tagColumns.get(i).trim();
+            int sourceIndex = getColumnIndex(sourceName, sourceColumnNames);
+            if (sourceColumnNames != null) {
+                sourceName = sourceColumnNames.get(sourceIndex);
+            }
+            ColumnInfo columnInfo = new ColumnInfo(
+                    ReportLine.FIELD_TAGS,
+                    sourceName,
+                    sourceIndex);
+            columnMapping.add(columnInfo);
+            targetColumnNames.add(sourceName);
+            LOGGER.info("  " + columnInfo.toString());
+        }
+    }
+
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @param self the object to generate the string for (typically this), used only for its class name.
+     */
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("targetColumnNames", targetColumnNames)
+                .add("sourceColumnNames", sourceColumnNames)
+                .add("columnMapping", columnMapping);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/parser/CommonFormat.java b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/CommonFormat.java
new file mode 100644
index 0000000..28b4242
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/CommonFormat.java
@@ -0,0 +1,304 @@
+/*
+ * 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.datalab.core.parser;
+
+import com.epam.datalab.exceptions.ParseException;
+import com.epam.datalab.model.aws.ReportLine;
+import org.apache.commons.lang3.StringUtils;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+/**
+ * Provides common format features.
+ */
+public class CommonFormat {
+    /**
+     * Character for separate field names and values.
+     */
+    public static final char FIELD_SEPARATOR = ',';
+
+    /**
+     * Character for termination field names and values.
+     */
+    public static final char FIELD_DELIMITER = '"';
+
+    /**
+     * Escape character.
+     */
+    public static final char ESCAPE_CHAR = '\\';
+
+    /**
+     * Default character used for decimal sign.
+     */
+    public static final char DECIMAL_SEPARATOR_DEFAULT = '.';
+
+    /**
+     * Default character used for thousands separator.
+     */
+    public static final char DECIMAL_GROUPING_SEPARATOR_DEFAULT = ' ';
+
+    /**
+     * String of the field separator for replacement to target data.
+     */
+    private static final String DELIMITER_REPLACE_FROM = String.valueOf(FIELD_DELIMITER);
+
+    /**
+     * String of the escaped field separator for replacement to target data.
+     */
+    private static final String DELIMITER_REPLACE_TO = new StringBuilder()
+            .append(ESCAPE_CHAR)
+            .append(FIELD_DELIMITER)
+            .toString();
+
+    /**
+     * Formatter for convert decimal numbers to string.
+     */
+    private static final DecimalFormat DECIMAL_TO_STRING_FORMAT;
+
+    static {
+        DECIMAL_TO_STRING_FORMAT = new DecimalFormat();
+        DecimalFormatSymbols symbols = new DecimalFormatSymbols();
+        symbols.setDecimalSeparator(DECIMAL_SEPARATOR_DEFAULT);
+        DECIMAL_TO_STRING_FORMAT.setDecimalFormatSymbols(symbols);
+        DECIMAL_TO_STRING_FORMAT.setGroupingUsed(false);
+        DECIMAL_TO_STRING_FORMAT.setMaximumFractionDigits(100);
+    }
+
+
+    /**
+     * Column meta information.
+     */
+    private final ColumnMeta columnMeta;
+
+    /**
+     * Formatter for parse of decimal number .
+     */
+    private final DecimalFormat sourceDecimalFormat;
+
+
+    /**
+     * Instantiate the helper for common format.
+     *
+     * @param columnMeta column meta information.
+     */
+    public CommonFormat(ColumnMeta columnMeta) {
+        this(columnMeta, DECIMAL_SEPARATOR_DEFAULT, DECIMAL_GROUPING_SEPARATOR_DEFAULT);
+    }
+
+    /**
+     * Instantiate the helper for common format.
+     *
+     * @param columnMeta        column meta information.
+     * @param decimalSeparator  the character used for decimal sign.
+     * @param groupingSeparator the character used for thousands separator.
+     */
+    public CommonFormat(ColumnMeta columnMeta, char sourceDecimalSeparator, char sourceGroupingSeparator) {
+        this.columnMeta = columnMeta;
+        this.sourceDecimalFormat = getDecimalFormat(sourceDecimalSeparator, sourceGroupingSeparator);
+    }
+
+
+    /**
+     * Create and return the target row for common format from source.
+     *
+     * @param sourceRow the source row.
+     * @return row in common format.
+     * @throws ParseException
+     */
+    public ReportLine toCommonFormat(List<String> sourceRow) throws ParseException {
+        if (columnMeta.getColumnMapping() == null) {
+            return toReportLine(sourceRow);
+        }
+
+        List<String> targetRow = new ArrayList<>();
+        for (ColumnInfo columnInfo : columnMeta.getColumnMapping()) {
+            targetRow.add((columnInfo.sourceIndex < 0 ? "" :
+                    (columnInfo.sourceIndex < sourceRow.size() ? sourceRow.get(columnInfo.sourceIndex) : null)));
+        }
+        return toReportLine(targetRow);
+    }
+
+    /**
+     * Add the column value to string in CSV format.
+     *
+     * @param sb    the buffer of sting.
+     * @param value the value.
+     * @return the buffer of string.
+     */
+    private static StringBuilder addToStringBuilder(StringBuilder sb, String value) {
+        if (sb.length() > 0) {
+            sb.append(FIELD_SEPARATOR);
+        }
+        return sb.append(FIELD_DELIMITER)
+                .append(StringUtils.replace(value, DELIMITER_REPLACE_FROM, DELIMITER_REPLACE_TO))
+                .append(FIELD_DELIMITER);
+    }
+
+    /**
+     * Convert row to line in CSV format.
+     *
+     * @param row row for convertation.
+     * @return string in CSV format.
+     */
+    public static String rowToString(List<String> row) {
+        StringBuilder sb = new StringBuilder();
+        for (String s : row) {
+            addToStringBuilder(sb, s);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Convert row to line in CSV format.
+     *
+     * @param row row for convertation.
+     * @return string in CSV format.
+     */
+    public static String rowToString(ReportLine row) {
+        StringBuilder sb = new StringBuilder();
+
+        addToStringBuilder(sb, row.getDatalabId());
+        addToStringBuilder(sb, row.getUser());
+        addToStringBuilder(sb, row.getUsageDate());
+        addToStringBuilder(sb, row.getProduct());
+        addToStringBuilder(sb, row.getUsageType());
+        addToStringBuilder(sb, doubleToString(row.getUsage()));
+        addToStringBuilder(sb, doubleToString(row.getCost()));
+        addToStringBuilder(sb, row.getCurrencyCode());
+        addToStringBuilder(sb, row.getResourceType().toString());
+        addToStringBuilder(sb, row.getResourceId());
+
+        if (row.getTags() != null) {
+            for (String key : row.getTags().keySet()) {
+                addToStringBuilder(sb, row.getTags().get(key));
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Create and return decimal formatter.
+     *
+     * @param decimalSeparator  the character used for decimal sign.
+     * @param groupingSeparator the character used for thousands separator.
+     * @return Formatter for decimal digits.
+     */
+    private DecimalFormat getDecimalFormat(char decimalSeparator, char groupingSeparator) {
+        DecimalFormat df = new DecimalFormat();
+        DecimalFormatSymbols symbols = new DecimalFormatSymbols();
+        symbols.setDecimalSeparator(decimalSeparator);
+        symbols.setGroupingSeparator(groupingSeparator);
+        df.setDecimalFormatSymbols(symbols);
+        return df;
+    }
+
+    /**
+     * Parse and return double value. If value is <b>null</b> or empty return zero.
+     *
+     * @param columnName the name of column.
+     * @param value      the value.
+     * @throws ParseException
+     */
+    public double parseDouble(String columnName, String value) throws ParseException {
+        if (value == null || value.trim().isEmpty()) {
+            return 0;
+        }
+        try {
+            return sourceDecimalFormat.parse(value).doubleValue();
+        } catch (Exception e) {
+            throw new ParseException("Cannot cast column " + columnName + " value \"" + value + "\" to double: " + e
+                    .getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Return the string representation of double value.
+     *
+     * @param value the value.
+     */
+    public static String doubleToString(double value) {
+        return DECIMAL_TO_STRING_FORMAT.format(value);
+    }
+
+    /**
+     * Creates and returns the line of billing report from the list of values.
+     *
+     * @param row the list of values.
+     * @return the line of billing report.
+     * @throws ParseException
+     */
+    public ReportLine toReportLine(List<String> row) throws ParseException {
+        if (row.size() < ColumnMeta.TAG_COLUMN_INDEX || row.size() > columnMeta.getTargetColumnNames().size()) {
+            throw new ParseException("Invalid the number of columns in list: expected from " + ColumnMeta
+                    .TAG_COLUMN_INDEX +
+                    " to " + columnMeta.getTargetColumnNames().size() + ", actual " + row.size());
+        }
+        ReportLine line = new ReportLine();
+        int i = 0;
+
+        line.setDatalabId(row.get(i));
+        line.setUser(row.get(++i));
+        line.setUsageDate(row.get(++i));
+        line.setProduct(row.get(++i));
+        line.setUsageType(row.get(++i));
+        line.setUsage(parseDouble("usage", row.get(++i)));
+        line.setCost(parseDouble("cost", row.get(++i)));
+        line.setCurrencyCode(row.get(++i));
+        line.setResourceTypeId(row.get(++i));
+
+        if (row.size() >= ColumnMeta.TAG_COLUMN_INDEX) {
+            LinkedHashMap<String, String> tags = new LinkedHashMap<>();
+            i++;
+            while (i < row.size()) {
+                tags.put(columnMeta.getTargetColumnNames().get(i), row.get(i++));
+            }
+            line.setTags(tags);
+        }
+
+        return line;
+    }
+
+
+    /**
+     * Print row to console.
+     *
+     * @param row array of values.
+     */
+    public static void printRow(String[] row) {
+        System.out.print(" | ");
+        for (String s : row) {
+            System.out.print(s + " | ");
+        }
+        System.out.println();
+    }
+
+    /**
+     * Print row to console.
+     *
+     * @param row list of values.
+     */
+    public static void printRow(List<String> row) {
+        printRow(row.toArray(new String[row.size()]));
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ConditionEvaluate.java b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ConditionEvaluate.java
new file mode 100644
index 0000000..abfd31e
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ConditionEvaluate.java
@@ -0,0 +1,168 @@
+/*
+ * 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.datalab.core.parser;
+
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.exceptions.ParseException;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.MapContext;
+import org.apache.commons.jexl3.internal.Script;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Evaluate condition for filtering source data.
+ */
+public class ConditionEvaluate {
+
+    /**
+     * Names of columns for condition.
+     */
+    private String[] columnNames;
+
+    /**
+     * Indexes of columns for condition.
+     */
+    private int[] columnIndexes;
+
+    /**
+     * JEXL expression for evaluation.
+     */
+    private final Script expression;
+
+    /**
+     * JEXL context to evaluate row.
+     */
+    private final JexlContext jexlContext;
+
+    /**
+     * Instantiate the engine to evaluate condition.
+     *
+     * @param columnNames the list of column names.
+     * @param condition   condition for filtering data.
+     * @throws InitializationException
+     */
+    public ConditionEvaluate(List<String> columnNames, String condition) throws InitializationException {
+        //Replace : to . in column names
+        List<String> colNames = new ArrayList<>(columnNames.size());
+        for (int i = 0; i < columnNames.size(); i++) {
+            String name = columnNames.get(i);
+            if (name.indexOf(':') > -1 && condition.indexOf(name) > -1) {
+                String newName = StringUtils.replaceChars(name, ':', '.');
+                colNames.add(newName);
+                condition = StringUtils.replace(condition, name, newName);
+            } else {
+                colNames.add(name);
+            }
+        }
+
+        try {
+            JexlEngine engine = new JexlBuilder().strict(true).silent(false).debug(true).create();
+            expression = (Script) engine.createExpression(condition);
+            jexlContext = new MapContext();
+        } catch (Exception e) {
+            throw new InitializationException("Cannot initialize JEXL engine for condition: " + condition + ". " +
+                    e.getLocalizedMessage(), e);
+        }
+
+        // Create mapping of columns for evaluations.
+        List<String> names = new ArrayList<>();
+        List<Integer> indexes = new ArrayList<>();
+        for (List<String> variableList : expression.getVariables()) {
+            String columnName = StringUtils.join(variableList, '.');
+            int index = getColumnIndex(colNames, columnName);
+            if (index == -1) {
+                throw new InitializationException("Unknow source column name \"" + columnName + "\" in condition: " +
+                        expression.getSourceText() + ". Known column names: " + StringUtils.join(columnNames, ", ") + ".");
+            }
+            names.add(columnName);
+            indexes.add(index);
+        }
+
+        this.columnNames = new String[names.size()];
+        this.columnIndexes = new int[indexes.size()];
+        for (int i = 0; i < indexes.size(); i++) {
+            this.columnNames[i] = names.get(i);
+            this.columnIndexes[i] = indexes.get(i);
+        }
+    }
+
+    /**
+     * Find and return the index of column in the given column list.
+     *
+     * @param columnNames the list of column names.
+     * @param columnName  the name of column to find.
+     */
+    private int getColumnIndex(List<String> columnNames, String columnName) {
+        for (int i = 0; i < columnNames.size(); i++) {
+            if (columnName.equals(columnNames.get(i))) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Evaluate condition for given row.
+     *
+     * @param row the row to evaluate.
+     * @return <true> if condition is true.
+     * @throws ParseException if condition is not return boolean type.
+     */
+    public boolean evaluate(List<String> row) throws ParseException {
+        for (int i = 0; i < columnNames.length; i++) {
+            jexlContext.set(columnNames[i], row.get(columnIndexes[i]));
+        }
+        Object value;
+        try {
+            value = expression.evaluate(jexlContext);
+        } catch (Exception e) {
+            throw new ParseException("Cannot evaluate condition: " + expression.getSourceText() + ". " +
+                    e.getLocalizedMessage(), e);
+        }
+        if (value instanceof Boolean) {
+            return (Boolean) value;
+        }
+        throw new ParseException("Invalid condition: " + expression.getSourceText());
+    }
+
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @param self the object to generate the string for (typically this), used only for its class name.
+     */
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("columnNames", columnNames)
+                .add("columnIndexes", columnIndexes);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ParserBase.java b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ParserBase.java
new file mode 100644
index 0000000..3b54850
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ParserBase.java
@@ -0,0 +1,395 @@
+/*
+ * 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.datalab.core.parser;
+
+import com.epam.datalab.core.AdapterBase;
+import com.epam.datalab.core.FilterBase;
+import com.epam.datalab.core.ModuleBase;
+import com.epam.datalab.core.aggregate.AggregateGranularity;
+import com.epam.datalab.core.aggregate.DataAggregator;
+import com.epam.datalab.exceptions.AdapterException;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.exceptions.ParseException;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.apache.commons.lang3.StringUtils;
+import org.bson.Document;
+
+import javax.validation.constraints.NotNull;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Abstract module of parser.<br>
+ * See description of {@link ModuleBase} how to create your own parser.
+ */
+public abstract class ParserBase extends ModuleBase {
+
+    /**
+     * Default character used for decimal sign.
+     */
+    public static final char DECIMAL_SEPARATOR_DEFAULT = '.';
+
+    /**
+     * Default character used for thousands separator.
+     */
+    public static final char DECIMAL_GROUPING_SEPARATOR_DEFAULT = ' ';
+
+    /**
+     * Name of key for date report data.
+     */
+    public static final String DATA_KEY_START_DATE = "ParserBase.maxStartDate";
+
+
+    /**
+     * Mapping columns from source format to target.
+     */
+    @JsonProperty
+    private String columnMapping = null;
+
+    /**
+     * Where condition for filtering the source data.
+     */
+    @JsonProperty
+    private String whereCondition = null;
+
+    /**
+     * How to aggregate the parsed data.
+     */
+    @JsonProperty
+    @NotNull
+    private AggregateGranularity aggregate = AggregateGranularity.NONE;
+
+    /**
+     * Character used for decimal sign of source data.
+     */
+    @JsonProperty
+    @NotNull
+    private char decimalSeparator = DECIMAL_SEPARATOR_DEFAULT;
+
+    /**
+     * Character used for thousands separator of source data.
+     */
+    @JsonProperty
+    @NotNull
+    private char groupingSeparator = DECIMAL_GROUPING_SEPARATOR_DEFAULT;
+
+
+    /**
+     * Adapter for reading source data.
+     */
+    @JsonIgnore
+    private AdapterBase adapterIn;
+
+    /**
+     * Adapter for writing converted data.
+     */
+    @JsonIgnore
+    private AdapterBase adapterOut;
+
+    /**
+     * Filter for source and converted data.
+     */
+    @JsonIgnore
+    private FilterBase filter;
+
+
+    /**
+     * Column meta information.
+     */
+    @JsonIgnore
+    private ColumnMeta columnMeta;
+
+    /**
+     * Condition for filtering the source data.
+     */
+    @JsonIgnore
+    private ConditionEvaluate condition;
+
+    /**
+     * Aggregator of billing report.
+     */
+    @JsonIgnore
+    private DataAggregator aggregator;
+
+    /**
+     * Common format helper.
+     */
+    @JsonIgnore
+    private CommonFormat commonFormat;
+
+    /**
+     * Parser statistics.
+     */
+    @JsonIgnore
+    private final List<ParserStatistics> statistics = new ArrayList<>();
+
+    /**
+     * Current parser statistics.
+     */
+    @JsonIgnore
+    ParserStatistics currentStatistics = null;
+
+
+    /**
+     * Return mapping columns from source format to target.
+     */
+    public String getColumnMapping() {
+        return columnMapping;
+    }
+
+    /**
+     * Set mapping columns from source format to target.
+     */
+    public void setColumnMapping(String columnMapping) {
+        this.columnMapping = columnMapping;
+    }
+
+    /**
+     * Return where condition for filtering the source data.
+     */
+    public String getWhereCondition() {
+        return whereCondition;
+    }
+
+    /**
+     * Set where condition for filtering the source data.
+     */
+    public void setWhereCondition(String whereCondition) {
+        this.whereCondition = whereCondition;
+    }
+
+    /**
+     * Return how to aggregate the parsed data.
+     */
+    public AggregateGranularity getAggregate() {
+        return aggregate;
+    }
+
+    /**
+     * Set how to aggregate the parsed data.
+     *
+     * @throws InitializationException
+     */
+    public void setAggregate(String aggregate) throws InitializationException {
+        if (aggregate == null) {
+            throw new InitializationException("Property aggregate cannot be null");
+        }
+        AggregateGranularity value = AggregateGranularity.of(aggregate);
+        if (value == null) {
+            throw new InitializationException("Invalid value \"" + aggregate + "\" for property aggregate. " +
+                    "Should be one of: " + StringUtils.join(AggregateGranularity.values(), ", "));
+        }
+        this.aggregate = value;
+    }
+
+    /**
+     * Return character used for decimal sign of source data.
+     */
+    public char getDecimalSeparator() {
+        return decimalSeparator;
+    }
+
+    /**
+     * Set character used for decimal sign of source data.
+     */
+    public void setDecimalSeparator(char decimalSeparator) {
+        this.decimalSeparator = decimalSeparator;
+    }
+
+    /**
+     * Return character used for thousands separator of source data.
+     */
+    public char getGroupingSeparator() {
+        return groupingSeparator;
+    }
+
+    /**
+     * Set character used for thousands separator of source data.
+     */
+    public void setGroupingSeparator(char groupingSeparator) {
+        this.groupingSeparator = groupingSeparator;
+    }
+
+
+    /**
+     * Return the adapter for reading source data.
+     */
+    public AdapterBase getAdapterIn() {
+        return adapterIn;
+    }
+
+    /**
+     * Return the adapter for writing converted data.
+     */
+    public AdapterBase getAdapterOut() {
+        return adapterOut;
+    }
+
+    /**
+     * Return the filter for source and converted data.
+     */
+    public FilterBase getFilter() {
+        return filter;
+    }
+
+    /**
+     * Return the column meta information.
+     */
+    public ColumnMeta getColumnMeta() {
+        return columnMeta;
+    }
+
+    /**
+     * Return the condition for filtering the source data.
+     */
+    public ConditionEvaluate getCondition() {
+        return condition;
+    }
+
+    /**
+     * Return the aggregator of billing report.
+     */
+    public DataAggregator getAggregator() {
+        return aggregator;
+    }
+
+    /**
+     * Return the common format helper.
+     */
+    public CommonFormat getCommonFormat() {
+        return commonFormat;
+    }
+
+    /**
+     * Return the parser statistics.
+     */
+    public List<ParserStatistics> getStatistics() {
+        return statistics;
+    }
+
+    /**
+     * Add and return the new instance for statistics.
+     *
+     * @param entryName the name of new entry.
+     */
+    public ParserStatistics addStatistics(String entryName) {
+        currentStatistics = new ParserStatistics(entryName);
+        statistics.add(currentStatistics);
+        return currentStatistics;
+    }
+
+    /**
+     * Return the current parser statistics.
+     */
+    public ParserStatistics getCurrentStatistics() {
+        return currentStatistics;
+    }
+
+
+    /**
+     * Initialize the parser.
+     *
+     * @throws InitializationException
+     */
+    public abstract void initialize() throws InitializationException;
+
+    /**
+     * Parse the source data to common format and write it to output adapter.
+     *
+     * @return
+     * @throws InitializationException
+     * @throws AdapterException
+     * @throws ParseException
+     */
+    public abstract List<Document> parse() throws InitializationException, AdapterException, ParseException;
+
+    /**
+     * Build parser from given modules.
+     *
+     * @param adapterIn  the adapter for reading source data.
+     * @param adapterOut the adapter for writing converted data.
+     * @param filter     the filter for source and converted data. May be <b>null<b>.
+     */
+    public ParserBase build(AdapterBase adapterIn, AdapterBase adapterOut, FilterBase filter) {
+        this.adapterIn = adapterIn;
+        this.adapterOut = adapterOut;
+        if (filter != null) {
+            filter.setParser(this);
+        }
+        this.filter = filter;
+        return this;
+    }
+
+
+    /**
+     * Initialize ParserBase.
+     *
+     * @param header - the header of source data.
+     * @throws InitializationException
+     * @throws AdapterException
+     */
+    protected void init(List<String> header) throws InitializationException, AdapterException {
+        columnMeta = new ColumnMeta(columnMapping, header);
+        if (whereCondition != null) {
+            if (columnMeta.getSourceColumnNames() == null) {
+                throw new InitializationException("To use the whereCondition property you must specify and have the header of source data");
+            }
+            condition = new ConditionEvaluate(columnMeta.getSourceColumnNames(), whereCondition);
+        } else {
+            condition = null;
+        }
+        commonFormat = new CommonFormat(columnMeta, decimalSeparator, groupingSeparator);
+
+        if (aggregate != AggregateGranularity.NONE) {
+            aggregator = new DataAggregator(aggregate);
+        }
+
+        if (getAdapterOut().isWriteHeader()) {
+            getAdapterOut().writeHeader(columnMeta.getTargetColumnNames());
+        }
+    }
+
+
+    /**
+     * Return the index of source column by column name.
+     *
+     * @param columnName the name of column.
+     * @throws InitializationException
+     */
+    public int getSourceColumnIndexByName(String columnName) throws InitializationException {
+        return ColumnMeta.getColumnIndexByName(columnName, columnMeta.getSourceColumnNames());
+    }
+
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("adapterIn", (adapterIn == null ? null : adapterIn.getType()))
+                .add("adapterOut", (adapterOut == null ? null : adapterOut.getType()))
+                .add("filter", (filter == null ? null : filter.getType()))
+                .add("columnMapping", columnMapping)
+                .add("whereCondition", whereCondition)
+                .add("aggregate", aggregate)
+                .add("decimalSeparator", decimalSeparator)
+                .add("groupingSeparator", groupingSeparator);
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ParserByLine.java b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ParserByLine.java
new file mode 100644
index 0000000..11f06cf
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ParserByLine.java
@@ -0,0 +1,249 @@
+/*
+ * 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.datalab.core.parser;
+
+import com.epam.datalab.core.ModuleBase;
+import com.epam.datalab.core.aggregate.AggregateGranularity;
+import com.epam.datalab.exceptions.AdapterException;
+import com.epam.datalab.exceptions.GenericException;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.exceptions.ParseException;
+import com.epam.datalab.model.aws.ReportLine;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.bson.Document;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Abstract module of parser by the line.<br>
+ * See description of {@link ModuleBase} how to create your own parser.
+ */
+public abstract class ParserByLine extends ParserBase {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ParserByLine.class);
+    private static final String ENTRY_NAME = "\nEntry name: ";
+    private static final String SOURCE_LINE = "\nSource line[";
+
+    /**
+     * Parse the header of source data and return it.
+     *
+     * @return the header of source data.
+     * @throws AdapterException
+     * @throws ParseException
+     */
+    public abstract List<String> parseHeader() throws AdapterException, ParseException;
+
+    /**
+     * Parse the row from source line and return result row.
+     *
+     * @param line the source line.
+     * @return the parsed row.
+     * @throws ParseException
+     */
+    public abstract List<String> parseRow(String line) throws ParseException;
+
+    /**
+     * Read the line from adapter and return it.
+     *
+     * @return the parsed row from adapterIn.
+     * @throws AdapterException
+     */
+    @JsonIgnore
+    public String getNextRow() throws AdapterException {
+        String line = getAdapterIn().readLine();
+        if (line == null) {
+            return null;
+        }
+        getCurrentStatistics().incrRowReaded();
+        return line;
+    }
+
+    /**
+     * Initialize ParserBase.
+     *
+     * @throws InitializationException
+     * @throws AdapterException
+     * @throws ParseException
+     */
+    protected boolean init() throws InitializationException, AdapterException, ParseException {
+        getAdapterIn().open();
+        LOGGER.debug("Source data has multy entry {}", getAdapterIn().hasMultyEntry());
+        if (!initEntry()) {
+            return false;
+        }
+        getAdapterOut().open();
+        return true;
+    }
+
+    /**
+     * Initialize for each entry ParserBase.
+     *
+     * @throws InitializationException
+     * @throws AdapterException
+     * @throws ParseException
+     */
+    private boolean initEntry() throws InitializationException, AdapterException, ParseException {
+        if (getAdapterIn().hasMultyEntry() && !getAdapterIn().hasEntryData()) {
+            return false;
+        }
+        addStatistics(getAdapterIn().getEntryName());
+        getCurrentStatistics().start();
+
+        super.init(parseHeader());
+        initialize();
+        if (getFilter() != null) {
+            getFilter().initialize();
+        }
+        return true;
+    }
+
+    /**
+     * Close adapters.
+     *
+     * @throws AdapterException
+     */
+    protected void close(boolean silent) throws AdapterException {
+        AdapterException ex = null;
+        try {
+            getAdapterIn().close();
+        } catch (Exception e) {
+            if (silent) {
+                LOGGER.warn("Cannot close adapterIn. {}", e.getLocalizedMessage(), e);
+            } else {
+                ex = new AdapterException("Cannot close adapterIn. " + e.getLocalizedMessage(), e);
+            }
+        }
+        try {
+            getAdapterOut().close();
+        } catch (Exception e) {
+            if (silent || ex != null) {
+                LOGGER.warn("Cannot close adapterOut. {}", e.getLocalizedMessage(), e);
+            } else {
+                ex = new AdapterException("Cannot close adapterOut. " + e.getLocalizedMessage(), e);
+            }
+        }
+        try {
+            getModuleData().closeMongoConnection();
+        } catch (IOException e) {
+            if (silent || ex != null) {
+                LOGGER.warn("Cannot close mongo connection. {}", e.getLocalizedMessage(), e);
+            } else {
+                ex = new AdapterException("Cannot close mongo connection. " + e.getLocalizedMessage(), e);
+            }
+        }
+        if (!silent && ex != null) {
+            throw ex;
+        }
+    }
+
+    /**
+     * Parse the source data to common format and write it to output adapter.
+     *
+     * @return list of billing data
+     * @throws InitializationException
+     * @throws AdapterException
+     * @throws ParseException
+     */
+    public List<Document> parse() throws InitializationException, AdapterException, ParseException {
+        List<Document> billingData = new ArrayList<>();
+        try {
+            if (init()) {
+                String line;
+                List<String> row;
+                ReportLine reportLine;
+                LOGGER.info("Parsing {}", getAdapterIn().getEntryName());
+
+                while ((line = getNextRow()) != null) {
+                    if (getFilter() != null && (line = getFilter().canParse(line)) == null) {
+                        getCurrentStatistics().incrRowFiltered();
+                        continue;
+                    }
+
+                    row = parseRow(line);
+                    if ((getFilter() != null && (row = getFilter().canTransform(row)) == null)) {
+                        getCurrentStatistics().incrRowFiltered();
+                        continue;
+                    }
+                    try {
+                        if (getCondition() != null && !getCondition().evaluate(row)) {
+                            getCurrentStatistics().incrRowFiltered();
+                            continue;
+                        }
+                    } catch (ParseException e) {
+                        throw new ParseException(e.getLocalizedMessage() + ENTRY_NAME + getCurrentStatistics().getEntryName() +
+                                SOURCE_LINE + getCurrentStatistics().getRowReaded() + "]: " + line, e);
+                    } catch (Exception e) {
+                        throw new ParseException("Cannot evaluate condition " + getWhereCondition() + ". " +
+                                e.getLocalizedMessage() + ENTRY_NAME + getCurrentStatistics().getEntryName() +
+                                SOURCE_LINE + getCurrentStatistics().getRowReaded() + "]: " + line, e);
+                    }
+
+                    try {
+                        reportLine = getCommonFormat().toCommonFormat(row);
+                    } catch (ParseException e) {
+                        throw new ParseException("Cannot cast row to common format. " +
+                                e.getLocalizedMessage() + ENTRY_NAME + getCurrentStatistics().getEntryName() +
+                                SOURCE_LINE + getCurrentStatistics().getRowReaded() + "]: " + line, e);
+                    }
+                    if (getFilter() != null && (reportLine = getFilter().canAccept(reportLine)) == null) {
+                        getCurrentStatistics().incrRowFiltered();
+                        continue;
+                    }
+
+                    getCurrentStatistics().incrRowParsed();
+                    if (getAggregate() != AggregateGranularity.NONE) {
+                        getAggregator().append(reportLine);
+                    } else {
+                        billingData.add(getAdapterOut().writeRow(reportLine));
+                        getCurrentStatistics().incrRowWritten();
+                    }
+                }
+
+                if (getAggregate() != AggregateGranularity.NONE) {
+                    for (int i = 0; i < getAggregator().size(); i++) {
+                        billingData.add(getAdapterOut().writeRow(getAggregator().get(i)));
+                        getCurrentStatistics().incrRowWritten();
+                    }
+                }
+            }
+        } catch (GenericException e) {
+            close(true);
+            if (getCurrentStatistics() != null) {
+                getCurrentStatistics().stop();
+            }
+            throw e;
+        } catch (Exception e) {
+            close(true);
+            if (getCurrentStatistics() != null) {
+                getCurrentStatistics().stop();
+            }
+            throw new ParseException("Unknown parser error. " + e.getLocalizedMessage(), e);
+        }
+
+        close(false);
+        if (getCurrentStatistics() != null) {
+            getCurrentStatistics().stop();
+        }
+        return billingData;
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ParserStatistics.java b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ParserStatistics.java
new file mode 100644
index 0000000..966bbd0
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/core/parser/ParserStatistics.java
@@ -0,0 +1,194 @@
+/*
+ * 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.datalab.core.parser;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+/**
+ * Store the statistic of parser processing.
+ */
+public class ParserStatistics {
+    /**
+     * Name of parsed entry.
+     */
+    private final String entryName;
+
+    /**
+     * Time is milliseconds when parser has been started.
+     */
+    private long timeStartInMillis = 0;
+
+    /**
+     * Parsing time in milliseconds.
+     */
+    private long elapsedTimeInMillis = 0;
+
+    /**
+     * Number of rows read.
+     */
+    private long rowReaded;
+
+    /**
+     * Number of rows skipped.
+     */
+    private long rowSkipped;
+
+    /**
+     * Number of rows filtered.
+     */
+    private long rowFiltered;
+
+    /**
+     * Number of rows parsed.
+     */
+    private long rowParsed;
+
+    /**
+     * Number of rows write.
+     */
+    private long rowWritten;
+
+
+    public ParserStatistics(String entryName) {
+        this.entryName = entryName;
+    }
+
+    public void start() {
+        timeStartInMillis = System.currentTimeMillis();
+        elapsedTimeInMillis = 0;
+        rowReaded = 0;
+        rowSkipped = 0;
+        rowFiltered = 0;
+        rowParsed = 0;
+        rowWritten = 0;
+    }
+
+    public void stop() {
+        if (timeStartInMillis != 0) {
+            elapsedTimeInMillis = System.currentTimeMillis() - timeStartInMillis;
+            timeStartInMillis = 0;
+        }
+    }
+
+
+    /**
+     * Return the name of parsed entry.
+     */
+    public String getEntryName() {
+        return entryName;
+    }
+
+    /**
+     * Return the elapsed time in milliseconds of initializing, reading, filtering, parsing and writing operations.
+     */
+    public long getElapsedTime() {
+        return (elapsedTimeInMillis != 0 ?
+                elapsedTimeInMillis :
+                timeStartInMillis == 0 ? 0 : System.currentTimeMillis() - timeStartInMillis);
+    }
+
+    /**
+     * Return the number of rows read.
+     */
+    public long getRowReaded() {
+        return rowReaded;
+    }
+
+    /**
+     * Return the number of rows skipped.
+     */
+    public long getRowSkipped() {
+        return rowSkipped;
+    }
+
+    /**
+     * Return the number of rows filtered.
+     */
+    public long getRowFiltered() {
+        return rowFiltered;
+    }
+
+    /**
+     * Return the number of rows parsed.
+     */
+    public long getRowParsed() {
+        return rowParsed;
+    }
+
+    /**
+     * Return the number of rows write.
+     */
+    public long getRowWritten() {
+        return rowWritten;
+    }
+
+    /**
+     * Increment the number of rows read.
+     */
+    public void incrRowReaded() {
+        rowReaded++;
+    }
+
+    /**
+     * Increment the number of rows skipped.
+     */
+    public void incrRowSkipped() {
+        rowSkipped++;
+    }
+
+    /**
+     * Increment the number of rows filtered.
+     */
+    public void incrRowFiltered() {
+        rowFiltered++;
+    }
+
+    /**
+     * Increment the number of rows parsed.
+     */
+    public void incrRowParsed() {
+        rowParsed++;
+    }
+
+    /**
+     * Increment the number of rows write.
+     */
+    public void incrRowWritten() {
+        rowWritten++;
+    }
+
+
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("entryName", entryName)
+                .add("elapsedTime", getElapsedTime())
+                .add("rowReaded", rowReaded)
+                .add("rowSkipped", rowSkipped)
+                .add("rowFiltered", rowFiltered)
+                .add("rowParsed", rowParsed)
+                .add("rowWritten", rowWritten);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/logging/AppenderBase.java b/services/billing-aws/src/main/java/com/epam/datalab/logging/AppenderBase.java
new file mode 100644
index 0000000..b3f7d97
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/logging/AppenderBase.java
@@ -0,0 +1,103 @@
+/*
+ * 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.datalab.logging;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.OutputStreamAppender;
+import com.epam.datalab.exceptions.InitializationException;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.TimeZone;
+
+/**
+ * Abstract class provides base configuration for the log appenders.
+ */
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
+public abstract class AppenderBase {
+
+    /**
+     * Log format pattern.
+     */
+    private final String logFormatPattern = "%-5p [%d{ISO8601," + TimeZone.getDefault().getID() + "}] %c: %m%n%rEx";
+
+    /**
+     * Perform configure of appender.
+     *
+     * @param context the context of logger.
+     */
+    public abstract void configure(LoggerContext context) throws InitializationException;
+
+    /**
+     * Perform the base configure of appender.
+     *
+     * @param context      the context of logger.
+     * @param appenderName the name of appender.
+     * @param appender     the class instance of appender.
+     */
+    public void configure(LoggerContext context, String appenderName, OutputStreamAppender<ILoggingEvent> appender) {
+        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
+        encoder.setPattern(logFormatPattern);
+        encoder.setContext(context);
+        encoder.start();
+
+        appender.setContext(context);
+        appender.setName(appenderName);
+        appender.setEncoder(encoder);
+        appender.start();
+
+        Logger logger = context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
+        logger.addAppender(appender);
+        logger.setAdditive(true);
+    }
+
+    /**
+     * Return the name of type for appender.
+     */
+    @JsonIgnore
+    public String getType() {
+        Class<? extends AppenderBase> clazz = this.getClass();
+        return (clazz.isAnnotationPresent(JsonTypeName.class) ?
+                clazz.getAnnotation(JsonTypeName.class).value() : clazz.getName());
+    }
+
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @param self the object to generate the string for (typically this), used only for its class name.
+     */
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("type", getType());
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .toString();
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/logging/AppenderConsole.java b/services/billing-aws/src/main/java/com/epam/datalab/logging/AppenderConsole.java
new file mode 100644
index 0000000..0987bbf
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/logging/AppenderConsole.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.logging;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.ConsoleAppender;
+import com.epam.datalab.exceptions.InitializationException;
+import com.fasterxml.jackson.annotation.JsonClassDescription;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+
+/**
+ * Console appender for logging.
+ */
+@JsonTypeName("console")
+@JsonClassDescription(
+        "Console log appender.\n" +
+                "Output log data to console. Does not have any properties.\n" +
+                "  - type: console"
+)
+public class AppenderConsole extends AppenderBase {
+
+    @Override
+    public void configure(LoggerContext context) throws InitializationException {
+        super.configure(context, "console-appender", new ConsoleAppender<ILoggingEvent>());
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/logging/AppenderFile.java b/services/billing-aws/src/main/java/com/epam/datalab/logging/AppenderFile.java
new file mode 100644
index 0000000..4ab53ad
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/logging/AppenderFile.java
@@ -0,0 +1,208 @@
+/*
+ * 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.datalab.logging;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.CoreConstants;
+import ch.qos.logback.core.FileAppender;
+import ch.qos.logback.core.rolling.DefaultTimeBasedFileNamingAndTriggeringPolicy;
+import ch.qos.logback.core.rolling.RollingFileAppender;
+import ch.qos.logback.core.rolling.TimeBasedFileNamingAndTriggeringPolicy;
+import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
+import com.epam.datalab.exceptions.InitializationException;
+import com.fasterxml.jackson.annotation.JsonClassDescription;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+/**
+ * File appender for logging. Support rolling files and archiving.
+ */
+@JsonTypeName("file")
+@JsonClassDescription(
+        "File log appender.\n" +
+                "Output log data to the file, if property archive is set to true then rolling\n" +
+                "mode is enabled. If archivedLogFilenamePattern ends with .gz or .zip extension\n" +
+                "then old log file will be compressed.\n" +
+                "  - type: file\n" +
+                "    currentLogFilename: <[path/]filename.log>  - pattern for log file naming.\n" +
+                "    [archive: <true | false>]                  - rolling log files or none.\n" +
+                "    [archivedLogFilenamePattern: <[path/]filename-%d{yyyy-MM-dd}.log[.gz | .zip]>]\n" +
+                "                                               - pattern for naming the archive log\n" +
+                "                                                 files.\n" +
+                "    [archivedFileCount: <number_of_days>]      - number of archive log file history."
+)
+public class AppenderFile extends AppenderBase {
+
+    /**
+     * The name of current log file.
+     */
+    @Valid
+    @NotNull
+    @JsonProperty
+    private String currentLogFilename;
+
+    /**
+     * Flag for archive of old files.
+     */
+    @Valid
+    @JsonProperty
+    private boolean archive = false;
+
+    /**
+     * Pattern for naming archive files. The compression mode depending on last
+     * letters of the fileNamePatternStr. Patterns ending with .gz imply GZIP
+     * compression, endings with '.zip' imply ZIP compression. Otherwise and by
+     * default, there is no compression.
+     */
+    @Valid
+    @JsonProperty
+    private String archivedLogFilenamePattern;
+
+    /**
+     * The maximum number of archive files to keep..
+     */
+    @Valid
+    @JsonProperty
+    private int archivedFileCount = CoreConstants.UNBOUND_HISTORY;
+
+
+    /**
+     * Return the name of current log file.
+     */
+    public String getCurrentLogFilename() {
+        return currentLogFilename;
+    }
+
+    /**
+     * Set the name of current log file.
+     */
+    public void setCurrentLogFilename(String currentLogFilename) {
+        this.currentLogFilename = currentLogFilename;
+    }
+
+    /**
+     * Return the flag for archive of old files.
+     */
+    public boolean getArchive() {
+        return archive;
+    }
+
+    /**
+     * Set the flag for archive of old files.
+     */
+    public void setArchive(boolean archive) {
+        this.archive = archive;
+    }
+
+    /**
+     * Return the pattern for naming archive files.
+     */
+    public String getArchivedLogFilenamePattern() {
+        return archivedLogFilenamePattern;
+    }
+
+    /**
+     * Set pattern for naming archive files. The compression mode depending on last
+     * letters of the fileNamePatternStr. Patterns ending with .gz imply GZIP
+     * compression, endings with '.zip' imply ZIP compression. Otherwise and by
+     * default, there is no compression.
+     * For example,
+     * /logs/application-%d{yyyy-MM-dd}.log.gz
+     */
+    public void setArchivedLogFilenamePattern(String archivedLogFilenamePattern) {
+        this.archivedLogFilenamePattern = archivedLogFilenamePattern;
+    }
+
+    /**
+     * Return the maximum number of archive files to keep..
+     */
+    public int getArchivedFileCount() {
+        return archivedFileCount;
+    }
+
+    /**
+     * Set the maximum number of archive files to keep..
+     */
+    public void setArchivedFileCount(int archivedFileCount) {
+        this.archivedFileCount = archivedFileCount;
+    }
+
+
+    @Override
+    public void configure(LoggerContext context) throws InitializationException {
+        if (currentLogFilename == null || currentLogFilename.trim().isEmpty()) {
+            throw new InitializationException("Configuration property logging.appenders.currentLogFilename cannot be null.");
+        }
+        super.configure(context, "file-appender", (archive ? getRollingFileAppender(context) : getFileAppender()));
+    }
+
+    /**
+     * Create and return synchronous the file appender.
+     */
+    private FileAppender<ILoggingEvent> getFileAppender() {
+        FileAppender<ILoggingEvent> appender = new FileAppender<>();
+        appender.setFile(currentLogFilename);
+        appender.setAppend(true);
+        return appender;
+    }
+
+    /**
+     * Create and return synchronous the rolling file appender.
+     *
+     * @param context the context of logger.
+     */
+    private RollingFileAppender<ILoggingEvent> getRollingFileAppender(LoggerContext context) throws InitializationException {
+        if (archivedLogFilenamePattern == null || archivedLogFilenamePattern.trim().isEmpty()) {
+            throw new InitializationException("Configuration property logging.appenders.archivedLogFilenamePattern cannot be null.");
+        }
+        RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();
+        appender.setFile(currentLogFilename);
+        appender.setAppend(true);
+
+        TimeBasedFileNamingAndTriggeringPolicy<ILoggingEvent> triggerPolicy = new DefaultTimeBasedFileNamingAndTriggeringPolicy<>();
+        triggerPolicy.setContext(context);
+
+        TimeBasedRollingPolicy<ILoggingEvent> rollPolicy = new TimeBasedRollingPolicy<>();
+        rollPolicy.setContext(context);
+        rollPolicy.setParent(appender);
+        rollPolicy.setFileNamePattern(archivedLogFilenamePattern);
+        rollPolicy.setMaxHistory(archivedFileCount);
+        rollPolicy.setTimeBasedFileNamingAndTriggeringPolicy(triggerPolicy);
+        rollPolicy.start();
+        appender.setRollingPolicy(rollPolicy);
+
+        return appender;
+    }
+
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("currentLogFilename", currentLogFilename)
+                .add("archive", archive)
+                .add("archivedLogFilenamePattern", archivedLogFilenamePattern)
+                .add("archivedFileCount", archivedFileCount);
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/module/AdapterConsole.java b/services/billing-aws/src/main/java/com/epam/datalab/module/AdapterConsole.java
new file mode 100644
index 0000000..bca08b5
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/module/AdapterConsole.java
@@ -0,0 +1,92 @@
+/*
+ * 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.datalab.module;
+
+import com.epam.datalab.core.AdapterBase;
+import com.epam.datalab.core.parser.CommonFormat;
+import com.epam.datalab.exceptions.AdapterException;
+import com.epam.datalab.model.aws.ReportLine;
+import com.fasterxml.jackson.annotation.JsonClassDescription;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import org.bson.Document;
+
+import java.util.List;
+
+/**
+ * The adapter for console output.
+ */
+@JsonTypeName(ModuleName.ADAPTER_CONSOLE)
+@JsonClassDescription(
+        "Console adapter.\n" +
+                "Output data to console. Can be used for AdapterOut only.\n" +
+                "  - type: " + ModuleName.ADAPTER_CONSOLE + "\n" +
+                "    [writeHeader: <true | false>]  - write header of data to the adapterOut."
+)
+public class AdapterConsole extends AdapterBase {
+
+    /**
+     * Default constructor for deserialization.
+     */
+    public AdapterConsole() {
+    }
+
+    /**
+     * Instantiate adapter for reading or writing.
+     *
+     * @param mode the mode of adapter.
+     */
+    public AdapterConsole(Mode mode) {
+        super(mode);
+    }
+
+
+    @Override
+    public void open() throws AdapterException {
+        if (getMode() != Mode.WRITE) {
+            throw new AdapterException("Mode of " + getType() + " adapter may be " + Mode.WRITE + " only.");
+        }
+    }
+
+    @Override
+    public void close() throws AdapterException {
+        // Nothing to do
+    }
+
+    @Override
+    public String getEntryName() {
+        return "console";
+    }
+
+    @Override
+    public String readLine() throws AdapterException {
+        throw new AdapterException("Unimplemented method called.");
+    }
+
+    @Override
+    public void writeHeader(List<String> header) {
+        System.out.println(CommonFormat.rowToString(header));
+    }
+
+    @Override
+    public Document writeRow(ReportLine row) {
+        System.out.println(CommonFormat.rowToString(row));
+        return null;
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/module/AdapterFile.java b/services/billing-aws/src/main/java/com/epam/datalab/module/AdapterFile.java
new file mode 100644
index 0000000..02af157
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/module/AdapterFile.java
@@ -0,0 +1,164 @@
+/*
+ * 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.datalab.module;
+
+import com.epam.datalab.core.AdapterBase;
+import com.epam.datalab.core.parser.CommonFormat;
+import com.epam.datalab.exceptions.AdapterException;
+import com.epam.datalab.model.aws.ReportLine;
+import com.fasterxml.jackson.annotation.JsonClassDescription;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.bson.Document;
+
+import javax.validation.constraints.NotNull;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * The adapter for file system.
+ */
+@JsonTypeName(ModuleName.ADAPTER_FILE)
+@JsonClassDescription(
+        "File adapter.\n" +
+                "Read source or write converted data to the file.\n" +
+                "  - type: " + ModuleName.ADAPTER_FILE + "\n" +
+                "    [writeHeader: <true | false>]  - write header of data to the adapterOut.\n" +
+                "    file: <filename>               - the name of file."
+)
+public class AdapterFile extends AdapterBase {
+
+    /**
+     * The name of file.
+     */
+    @NotNull
+    @JsonProperty
+    private String file;
+    /**
+     * Reader for adapter.
+     */
+    @JsonIgnore
+    private BufferedReader reader;
+    /**
+     * Writer for adapter.
+     */
+    @JsonIgnore
+    private BufferedWriter writer;
+
+    /**
+     * Return the name of file.
+     */
+    public String getFile() {
+        return file;
+    }
+
+    /**
+     * Set the name of file.
+     */
+    public void setFile(String file) {
+        this.file = file;
+    }
+
+    @Override
+    public void open() throws AdapterException {
+        try {
+            if (getMode() == Mode.READ) {
+                reader = new BufferedReader(new FileReader(file));
+            } else if (getMode() == Mode.WRITE) {
+                writer = new BufferedWriter(new FileWriter(file));
+            } else {
+                throw new AdapterException("Mode of adapter unknown or not defined. Set mode to " + Mode.READ + " or " + Mode.WRITE + ".");
+            }
+        } catch (Exception e) {
+            throw new AdapterException("Cannot open file " + file + ". " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    @Override
+    public void close() throws AdapterException {
+        if (reader != null) {
+            try {
+                reader.close();
+            } catch (IOException e) {
+                throw new AdapterException("Cannot close file " + file + ". " + e.getLocalizedMessage(), e);
+            } finally {
+                reader = null;
+            }
+        }
+
+        if (writer != null) {
+            try {
+                writer.close();
+            } catch (IOException e) {
+                throw new AdapterException("Cannot close file " + file + ". " + e.getLocalizedMessage(), e);
+            } finally {
+                writer = null;
+            }
+        }
+    }
+
+    @Override
+    public String getEntryName() {
+        return getFile();
+    }
+
+    @Override
+    public String readLine() throws AdapterException {
+        try {
+            return reader.readLine();
+        } catch (IOException e) {
+            throw new AdapterException("Cannot read file " + file + ". " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    @Override
+    public void writeHeader(List<String> header) throws AdapterException {
+        try {
+            writer.write(CommonFormat.rowToString(header));
+            writer.write(System.lineSeparator());
+        } catch (IOException e) {
+            throw new AdapterException("Cannot write file " + file + ". " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    @Override
+    public Document writeRow(ReportLine row) throws AdapterException {
+        try {
+            writer.write(CommonFormat.rowToString(row));
+            writer.write(System.lineSeparator());
+        } catch (IOException e) {
+            throw new AdapterException("Cannot write file " + file + ". " + e.getLocalizedMessage(), e);
+        }
+        return null;
+    }
+
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("file", file);
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/module/ModuleName.java b/services/billing-aws/src/main/java/com/epam/datalab/module/ModuleName.java
new file mode 100644
index 0000000..a72bb06
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/module/ModuleName.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.datalab.module;
+
+/**
+ * Names of billing tool modules.
+ */
+public class ModuleName {
+    public static final String ADAPTER_CONSOLE = "console";
+    public static final String ADAPTER_AGG_CONSOLE = "aggConsole";
+    public static final String ADAPTER_FILE = "file";
+    public static final String ADAPTER_S3_FILE = "s3file";
+    public static final String ADAPTER_MONGO_DATALAB = "mongodatalab";
+    public static final String PARSER_CSV = "csv";
+    public static final String FILTER_AWS = "aws";
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/module/ParserCsv.java b/services/billing-aws/src/main/java/com/epam/datalab/module/ParserCsv.java
new file mode 100644
index 0000000..7a4bc2b
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/module/ParserCsv.java
@@ -0,0 +1,312 @@
+/*
+ * 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.datalab.module;
+
+import com.epam.datalab.core.parser.ParserByLine;
+import com.epam.datalab.exceptions.AdapterException;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.exceptions.ParseException;
+import com.fasterxml.jackson.annotation.JsonClassDescription;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.validation.constraints.NotNull;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Parse CSV format to common CSV format.
+ */
+@JsonTypeName(ModuleName.PARSER_CSV)
+@JsonClassDescription(
+        "CSV parser.\n" +
+                "Parse source CSV format to common billing report.\n" +
+                "  - type: " + ModuleName.PARSER_CSV + "\n" +
+                "    [dataFile: <filename>]           - the file name to store working data of parser.]\n" +
+                "    [columnStartDate: <column_name>] - the name of source column with date of data.]\n" +
+                "    [columnMapping: >-\n" +
+                "                    <targetColumn1=sourceColumnX;targetColumn2=sourceColumnY; ...;\n" +
+                "                     tags=sourceColumnK,...,sourceColumnN>]\n" +
+                "                                  - columns mapping to target from source columns.\n" +
+                "                                    Know target columns: datalab_id, user,\n" +
+                "                                    usage_date, product, usage_type, usage, cost,\n" +
+                "                                    currency_code, resource_id, tags.\n" +
+                "    [whereCondition: >-\n" +
+                "                    <(source_columnX > 0.0 || source_columnY == 'string') &&\n" +
+                "                     source_columnZ != 2016>]\n" +
+                "                                  - where condition for filtering the source data,\n" +
+                "                                    see http://commons.apache.org/proper/commons-jexl/reference/syntax.html#Operators\n" +
+                "                                    for detais.\n" +
+                "    [aggregate: <none | month | day>] - how to aggregate the data.\n" +
+                "    [headerLineNo: <number>]          - the number of header line in source data.\n" +
+                "    [skipLines: <numbber>]            - the number of line which will be skipped\n" +
+                "                                        (include header).\n" +
+                "    [fieldSeparator: <char>]          - char for separate field names and values.\n" +
+                "    [fieldTerminator: <char>]         - char for terminate field names and values.\n" +
+                "    [escapeChar: <char>]              - escape char.\n" +
+                "    [decimalSeparator: <char>]        - char for decimal sign.\n" +
+                "    [groupingSeparator: <char>]       - char for thousands separator.\n"
+)
+public class ParserCsv extends ParserByLine {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ParserCsv.class);
+
+    /**
+     * Character for separate field names and values.
+     */
+    public static final char FIELD_SEPARATOR_DEFAULT = ',';
+
+    /**
+     * Character for termination field names and values.
+     */
+    public static final char FIELD_DELIMITER_DEFAULT = '"';
+
+    /**
+     * Escape character.
+     */
+    public static final char ESCAPE_CHAR_DEFAULT = '\\';
+
+
+    /**
+     * Character for separate field names and values.
+     */
+    @NotNull
+    @JsonProperty
+    private char fieldSeparator = FIELD_SEPARATOR_DEFAULT;
+
+    /**
+     * Character for termination field names and values.
+     */
+    @NotNull
+    @JsonProperty
+    private char fieldTerminator = FIELD_DELIMITER_DEFAULT;
+
+    /**
+     * Escape character.
+     */
+    @NotNull
+    @JsonProperty
+    private char escapeChar = ESCAPE_CHAR_DEFAULT;
+
+    /**
+     * The number of line that contain the header of data.
+     */
+    @JsonProperty
+    private int headerLineNo = 0;
+
+    /**
+     * The number of line which will be skipped (include header).
+     */
+    @JsonProperty
+    private int skipLines = 0;
+
+
+    /**
+     * Return the character for separate field names and values.
+     */
+    public char getFieldSeparator() {
+        return fieldSeparator;
+    }
+
+    /**
+     * Set the character for separate field names and values.
+     */
+    public void setFieldSeparator(char fieldSeparator) {
+        this.fieldSeparator = fieldSeparator;
+    }
+
+    /**
+     * Return the character for termination field names and values.
+     */
+    public char getFieldTerminator() {
+        return fieldTerminator;
+    }
+
+    /**
+     * Set the character for termination field names and values.
+     */
+    public void setFieldTerminator(char fieldTerminator) {
+        this.fieldTerminator = fieldTerminator;
+    }
+
+    /**
+     * Return the escape character.
+     */
+    public char getEscapeChar() {
+        return escapeChar;
+    }
+
+    /**
+     * Set the escape character.
+     */
+    public void setEscapeChar(char escapeChar) {
+        this.escapeChar = escapeChar;
+    }
+
+    /**
+     * Return the number of line that contain the header of data.
+     */
+    public int getHeaderLineNo() {
+        return headerLineNo;
+    }
+
+    /**
+     * Set the number of line that contain the header of data.
+     */
+    public void setHeaderLineNo(int headerLineNo) {
+        this.headerLineNo = headerLineNo;
+    }
+
+    /**
+     * Return the number of line which will be skipped (include header).
+     */
+    public int getSkipLines() {
+        return skipLines;
+    }
+
+    /**
+     * Set the number of line which will be skipped (include header).
+     */
+    public void setSkipLines(int skipLines) {
+        this.skipLines = skipLines;
+    }
+
+
+    @Override
+    public void initialize() throws InitializationException {
+    }
+
+    @Override
+    public List<String> parseHeader() throws AdapterException, ParseException {
+        String line = null;
+        List<String> header = null;
+
+        if (headerLineNo > 0) {
+            while (getCurrentStatistics().getRowReaded() < headerLineNo) {
+                if ((line = getNextRow()) == null) {
+                    return null;
+                }
+                getCurrentStatistics().incrRowSkipped();
+            }
+            header = parseRow(line);
+        }
+
+        while (getCurrentStatistics().getRowReaded() < skipLines) {
+            if (getNextRow() == null) {
+                break;
+            }
+            getCurrentStatistics().incrRowSkipped();
+        }
+
+        return header;
+    }
+
+
+    /**
+     * Construct the exception.
+     *
+     * @param message    the error message.
+     * @param pos        the position in the parsed line.
+     * @param sourceLine the parsed line.
+     * @return ParseException
+     */
+    private ParseException getParseException(String message, int pos, String sourceLine) {
+        String s = String.format("%s at pos %d in line: ", message, pos);
+        LOGGER.error(s + sourceLine);
+        LOGGER.error(StringUtils.repeat(' ', s.length() + pos - 1) + '^');
+        return new ParseException(s + sourceLine);
+    }
+
+    @Override
+    public List<String> parseRow(String line) throws ParseException {
+        int realPos = 0;
+        int pos = 0;
+        boolean isDelimiter = false;
+        StringBuilder sb = new StringBuilder(line);
+        List<String> row = new ArrayList<>();
+
+        while (pos < sb.length()) {
+            char c = sb.charAt(pos);
+            if (c == escapeChar) {
+                realPos++;
+                pos++;
+                if (pos == sb.length()) {
+                    throw getParseException("Invalid escape char", realPos, line);
+                }
+                sb.delete(pos - 1, pos);
+                realPos++;
+            } else if (c == fieldTerminator) {
+                realPos++;
+                if (isDelimiter) {
+                    realPos++;
+                    pos++;
+                    if (pos == sb.length()) {
+                        sb.delete(pos - 1, pos);
+                        break;
+                    }
+                    if (sb.charAt(pos) == fieldSeparator) {
+                        row.add(sb.substring(0, pos - 1));
+                        sb.delete(0, pos + 1);
+                        pos = 0;
+                        isDelimiter = false;
+                        continue;
+                    }
+                    throw getParseException("Invalid field delimiter", realPos, line);
+                }
+
+                if (pos != 0) {
+                    throw getParseException("Unterminated field", realPos, line);
+                }
+                sb.delete(0, 1);
+                isDelimiter = true;
+                continue;
+            } else if (c == fieldSeparator) {
+                realPos++;
+                if (isDelimiter) {
+                    pos++;
+                    continue;
+                }
+                row.add(sb.substring(0, pos));
+                sb.delete(0, pos + 1);
+                pos = 0;
+            } else {
+                realPos++;
+                pos++;
+            }
+        }
+        row.add(sb.toString());
+
+        return row;
+    }
+
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("fieldSeparator", fieldSeparator)
+                .add("fieldTerminator", fieldTerminator)
+                .add("escapeChar", escapeChar)
+                .add("headerLineNo", headerLineNo)
+                .add("skipLines", skipLines);
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/module/aws/AdapterS3File.java b/services/billing-aws/src/main/java/com/epam/datalab/module/aws/AdapterS3File.java
new file mode 100644
index 0000000..5bd7680
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/module/aws/AdapterS3File.java
@@ -0,0 +1,388 @@
+/*
+ * 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.datalab.module.aws;
+
+import com.amazonaws.auth.BasicAWSCredentials;
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.AmazonS3Client;
+import com.amazonaws.services.s3.model.GetObjectRequest;
+import com.amazonaws.services.s3.model.S3Object;
+import com.epam.datalab.core.AdapterBase;
+import com.epam.datalab.exceptions.AdapterException;
+import com.epam.datalab.model.aws.ReportLine;
+import com.epam.datalab.module.ModuleName;
+import com.fasterxml.jackson.annotation.JsonClassDescription;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.bson.Document;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.validation.constraints.NotNull;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * The adapter for S3 file system of Amazon.
+ */
+@JsonTypeName(ModuleName.ADAPTER_S3_FILE)
+@JsonClassDescription(
+        "Amazon S3 file system adapter.\n" +
+                "Read source or write converted data to the file in Amazon S3 bucket.\n" +
+                "  - type: " + ModuleName.ADAPTER_S3_FILE + "\n" +
+                "    [writeHeader: <true | false>]   - write header of data to the adapterOut.\n" +
+                "    bucket: <bucketname>            - the name of S3 bucket.\n" +
+                "    path: <path>                    - the path to the report or empty if used the root folder.\n" +
+                "    accountId: <AWS account number> - the account number, see for details\n" +
+                "                                      \"Detailed billing report with resources and tags\"\n" +
+                "                                      http://docs.aws.amazon" +
+                ".com/awsaccountbilling/latest/aboutv2/billing-reports.html#detailed-report-with-resources-tags\n" +
+                "    [accessKeyId: <string>]         - Amazon access key ID.\n" +
+                "    [secretAccessKey: <string>]     - Amazon secret access key."
+)
+public class AdapterS3File extends AdapterBase {
+    /**
+     * Name of key for the last loaded file.
+     */
+    public static final String DATA_KEY_LAST_LOADED_FILE = "AdapterS3File_lastLoadedFile";
+    /**
+     * Name of key for the modification date of loaded file.
+     */
+    public static final String DATA_KEY_LAST_MODIFICATION_DATE = "AdapterS3File_lastModifyDate";
+    private static final Logger LOGGER = LoggerFactory.getLogger(AdapterS3File.class);
+    private static final String CANNOT_READ_FILE_FORMAT = "Cannot read file %s. %s";
+    private static final String DELIMITER = "/";
+
+    /**
+     * The name of bucket.
+     */
+    @NotNull
+    @JsonProperty
+    private String bucket;
+
+    /**
+     * The path to report.
+     */
+    @JsonProperty
+    private String path;
+
+    /**
+     * AWS account number.
+     */
+    @NotNull
+    @JsonProperty
+    private String accountId;
+
+    /**
+     * Access key ID for Amazon Web Services.
+     */
+    @JsonProperty
+    private String accessKeyId;
+
+    /**
+     * Secret key for Amazon Web Services.
+     */
+    @JsonProperty
+    private String secretAccessKey;
+
+    @JsonProperty
+    private boolean awsJobEnabled;
+    /**
+     * List of report files for loading.
+     */
+    @JsonIgnore
+    private List<String> filelist = null;
+    /**
+     * Index of current report file.
+     */
+    @JsonIgnore
+    private int currentFileIndex = -1;
+    /**
+     * Index of current report file.
+     */
+    @JsonIgnore
+    private String entryName = null;
+    /**
+     * Amazon S3 client.
+     */
+    @JsonIgnore
+    private AmazonS3 clientS3 = null;
+    /**
+     * Amazon S3 client.
+     */
+    @JsonIgnore
+    private Date lastModificationDate = null;
+    /**
+     * File input stream.
+     */
+    @JsonIgnore
+    private InputStream fileInputStream = null;
+    /**
+     * Reader for adapter.
+     */
+    @JsonIgnore
+    private BufferedReader reader = null;
+
+    /**
+     * Return the name of bucket.
+     */
+    public String getBucket() {
+        return bucket;
+    }
+
+    /**
+     * Set the name of bucket.
+     */
+    public void setBucket(String bucket) {
+        this.bucket = bucket;
+    }
+
+    /**
+     * Return the path to report.
+     */
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * Set the path to report.
+     */
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    /**
+     * Return the AWS account number.
+     */
+    public String getAccountId() {
+        return accountId;
+    }
+
+    /**
+     * Set the AWS account number.
+     */
+    public void setAccountId(String accountId) {
+        this.accountId = accountId;
+    }
+
+    /**
+     * Return the access key ID for Amazon Web Services.
+     */
+    public String getAccessKeyId() {
+        return this.accessKeyId;
+    }
+
+    /**
+     * Set the access key ID for Amazon Web Services.
+     */
+    public void setAccessKeyId(String accessKeyId) {
+        this.accessKeyId = accessKeyId;
+    }
+
+    /**
+     * Return the secret key for Amazon Web Services.
+     */
+    public String getSecretAccessKey() {
+        return this.secretAccessKey;
+    }
+
+    /**
+     * Set the secret key for Amazon Web Services.
+     */
+    public void setSecretAccessKey(String secretAccessKey) {
+        this.secretAccessKey = secretAccessKey;
+    }
+
+    @Override
+    public void open() throws AdapterException {
+        LOGGER.debug("Adapter S3 will be opened for {}", getMode());
+        if (getMode() == Mode.READ) {
+            setLastModificationDate();
+            clientS3 = getAmazonClient();
+            S3FileList s3files = new S3FileList(awsJobEnabled, bucket, getModuleData());
+            filelist = s3files.getFiles(clientS3);
+            currentFileIndex = (filelist.isEmpty() ? -1 : 0);
+            fileInputStream = null;
+            reader = null;
+            entryName = null;
+            openNextEntry();
+            LOGGER.debug("Adapter S3 has been opened");
+        } else if (getMode() == Mode.WRITE) {
+            throw new AdapterException("Unsupported mode " + Mode.WRITE + ".");
+        } else {
+            throw new AdapterException("Mode of adapter unknown or not defined. Set mode to " + Mode.READ + ".");
+        }
+    }
+
+    @Override
+    public boolean hasMultyEntry() {
+        return true;
+    }
+
+    @Override
+    public boolean openNextEntry() throws AdapterException {
+        String filename = getCurrentFileName();
+        if (filename == null) {
+            if (filelist.isEmpty()) {
+                final String reportPath = path == null ? bucket : bucket + DELIMITER + path;
+                LOGGER.debug("New report files in bucket folder {} not found", reportPath);
+            }
+            return false;
+        }
+        entryName = filename;
+        LOGGER.debug("Open a next entry in file {}", filename);
+        reader = new BufferedReader(new InputStreamReader(getFileStream()));
+        try {
+            getModuleData().setId(filename);
+            getModuleData().setModificationDate(lastModificationDate);
+            getModuleData().set(DATA_KEY_LAST_LOADED_FILE, filename);
+            getModuleData().set(DATA_KEY_LAST_MODIFICATION_DATE, lastModificationDate);
+            getModuleData().store();
+        } catch (Exception e) {
+            throw new AdapterException(e.getLocalizedMessage(), e);
+        }
+        currentFileIndex++;
+        return false;
+    }
+
+    @Override
+    public boolean hasEntryData() {
+        return (reader != null);
+    }
+
+    @Override
+    public void close() throws AdapterException {
+        closeFile(getCurrentFileName());
+    }
+
+    @Override
+    public String getEntryName() {
+        return entryName;
+    }
+
+    @Override
+    public String readLine() throws AdapterException {
+        try {
+            return reader.readLine();
+        } catch (IOException e) {
+            throw new AdapterException(String.format(CANNOT_READ_FILE_FORMAT, getCurrentFileName(), e
+                    .getLocalizedMessage()), e);
+        }
+    }
+
+    @Override
+    public void writeHeader(List<String> header) throws AdapterException {
+        throw new AdapterException("Unimplemented method.");
+    }
+
+    @Override
+    public Document writeRow(ReportLine row) throws AdapterException {
+        throw new AdapterException("Unimplemented method.");
+    }
+
+    /**
+     * Return the current file name.
+     */
+    public String getCurrentFileName() {
+        return (filelist == null || currentFileIndex < 0 || currentFileIndex >= filelist.size() ? null : filelist.get
+                (currentFileIndex));
+    }
+
+    /**
+     * Creates and returns the Amazon client, as well as checks bucket existence.
+     *
+     * @throws AdapterException
+     */
+    private AmazonS3 getAmazonClient() throws AdapterException {
+        AmazonS3 s3 = (accessKeyId == null ?
+                new AmazonS3Client() :
+                new AmazonS3Client(new BasicAWSCredentials(accessKeyId, secretAccessKey)));
+
+        if (!s3.doesBucketExist(bucket)) {
+            throw new AdapterException("Bucket \"" + bucket + "\" does not exist.");
+        }
+
+        return s3;
+    }
+
+    /**
+     * Open the source file and return reader.
+     *
+     * @throws AdapterException
+     */
+    private InputStream getFileStream() throws AdapterException {
+        try {
+            GetObjectRequest request = new GetObjectRequest(bucket, getCurrentFileName());
+            S3Object object = clientS3.getObject(request);
+            lastModificationDate = object.getObjectMetadata().getLastModified();
+            return object.getObjectContent();
+        } catch (Exception e) {
+            throw new AdapterException("Cannot open file " + bucket + DELIMITER + getCurrentFileName() + ". " + e
+                    .getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Return the modification date of loaded file.
+     *
+     * @throws AdapterException
+     */
+    private void setLastModificationDate() throws AdapterException {
+        try {
+            lastModificationDate = getModuleData().getDate(DATA_KEY_LAST_MODIFICATION_DATE);
+        } catch (Exception e) {
+            throw new AdapterException("Cannot get the last modification date for report. " + e.getLocalizedMessage(),
+                    e);
+        }
+    }
+
+    /**
+     * Close a zip file.
+     *
+     * @param filename file name.
+     * @throws AdapterException
+     */
+    private void closeFile(String filename) throws AdapterException {
+        if (fileInputStream != null) {
+            try {
+                fileInputStream.close();
+            } catch (IOException e) {
+                throw new AdapterException("Cannot close file " + filename + ". " + e.getLocalizedMessage(), e);
+            }
+            fileInputStream = null;
+        }
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("bucket", bucket)
+                .add("path", path)
+                .add("accountId", accountId)
+                .add("accessKeyId", "***")
+                .add("secretAccessKey", "***");
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/module/aws/FilterAWS.java b/services/billing-aws/src/main/java/com/epam/datalab/module/aws/FilterAWS.java
new file mode 100644
index 0000000..71154b5
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/module/aws/FilterAWS.java
@@ -0,0 +1,150 @@
+/*
+ * 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.datalab.module.aws;
+
+import com.epam.datalab.core.FilterBase;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.model.aws.ReportLine;
+import com.epam.datalab.module.ModuleName;
+import com.fasterxml.jackson.annotation.JsonClassDescription;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * Filter and transform the line of AWS detailed billing reports.
+ */
+@JsonTypeName(ModuleName.FILTER_AWS)
+@JsonClassDescription(
+        "Amazon Web Services detailed billing reports filter.\n" +
+                "Filter report data and select line item only. Set column projectCode and\n" +
+                "currencyCode to user values.\n" +
+                "  - type: " + ModuleName.FILTER_AWS + "\n" +
+                "    [currencyCode: <string>]    - user value for currencyCode column.\n" +
+                "    [columnDatalabTag: <string>]   - name of column tag of DataLab resource id.\n" +
+                "    [serviceBaseName: <string>] - DataLab's service base name."
+
+)
+public class FilterAWS extends FilterBase {
+
+    /**
+     * The code of currency.
+     */
+    @NotNull
+    @JsonProperty
+    private String currencyCode;
+
+    /**
+     * Name of report column tag of DataLab.
+     */
+    @NotNull
+    @JsonProperty
+    private String columnDatalabTag;
+
+    /**
+     * DataLab service base name.
+     */
+    @NotNull
+    @JsonProperty
+    private String serviceBaseName;
+    private int datalabIdIndex = -1;
+    private String datalabPrefix;
+
+    /**
+     * Return the code of currency for billing.
+     */
+    public String getCurrencyCode() {
+        return currencyCode;
+    }
+
+    /**
+     * Set the code of currency for billing.
+     */
+    public void setCurrencyCode(String currencyCode) {
+        this.currencyCode = currencyCode;
+    }
+
+    /**
+     * Return the name of report column tag of DataLab.
+     */
+    public String getColumnDatalabTag() {
+        return columnDatalabTag;
+    }
+
+    /**
+     * Set the name of report column tag of DataLab.
+     */
+    public void setDatalabTagName(String columnDatalabTag) {
+        this.columnDatalabTag = columnDatalabTag;
+    }
+
+    /**
+     * Return service base name.
+     */
+    public String getServiceBaseName() {
+        return serviceBaseName;
+    }
+
+    /**
+     * Set service base name.
+     */
+    public void setServiceBaseName(String serviceBaseName) {
+        this.serviceBaseName = serviceBaseName;
+    }
+
+    @Override
+    public void initialize() throws InitializationException {
+        datalabIdIndex = (getColumnDatalabTag() == null ? -1 :
+                getParser().getSourceColumnIndexByName(getColumnDatalabTag()));
+        datalabPrefix = getServiceBaseName() + ":";
+    }
+
+    @Override
+    public String canParse(String line) {
+        return line;
+    }
+
+    @Override
+    public List<String> canTransform(List<String> row) {
+        if (datalabIdIndex != -1 &&
+                (row.size() <= datalabIdIndex ||
+                        !row.get(datalabIdIndex).startsWith(datalabPrefix))) {
+            return null;
+        }
+        return row;
+    }
+
+    @Override
+    public ReportLine canAccept(ReportLine row) {
+        row.setCurrencyCode(currencyCode);
+        return row;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("currencyCode", currencyCode)
+                .add("columnDatalabTag", columnDatalabTag)
+                .add("serviceBaseName", serviceBaseName);
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/module/aws/S3FileList.java b/services/billing-aws/src/main/java/com/epam/datalab/module/aws/S3FileList.java
new file mode 100644
index 0000000..719aad8
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/module/aws/S3FileList.java
@@ -0,0 +1,168 @@
+/*
+ * 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.datalab.module.aws;
+
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.model.ListObjectsV2Request;
+import com.amazonaws.services.s3.model.ListObjectsV2Result;
+import com.amazonaws.services.s3.model.S3ObjectSummary;
+import com.epam.datalab.core.ModuleData;
+import com.epam.datalab.exceptions.AdapterException;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static java.util.stream.Collectors.mapping;
+import static java.util.stream.Collectors.toList;
+
+/**
+ * Create a file listing of reports from AWS bucket.
+ * See details in
+ * <a href="http://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/billing-reports.html#detailed-report-with-resources-tags">
+ * Detailed billing report with resources and tags</a>.
+ */
+public class S3FileList {
+
+    /**
+     * Report suffix without date.
+     */
+    private static final String REPORT_SUFIX = ".csv";
+    /**
+     * Date regex for YYYYMMDD
+     */
+    private static final String DATE_REGEX = "\\d{4}(0?[1-9]|1[012])(0?[1-9]|[12][0-9]|3[01])";
+    private static final String REGEX = String.format("(^.*/.*/%s-%s)/.*/*.\\%s", DATE_REGEX, DATE_REGEX,
+            REPORT_SUFIX);
+
+    /**
+     * Bucket name.
+     */
+    private final String bucket;
+
+    /**
+     * Name of last file which is loaded or <b>null</b> for loading all files in bucket folder.
+     */
+    private final ModuleData moduleData;
+    private final Pattern reportPattern;
+    private final boolean awsJobEnabled;
+
+
+    /**
+     * Instantiate file find class.
+     *
+     * @param awsJobEnabled
+     * @param bucket        the name of bucket.
+     * @param moduleData    data for working module
+     */
+    public S3FileList(boolean awsJobEnabled, String bucket, ModuleData moduleData) {
+        this.bucket = bucket;
+        this.moduleData = moduleData;
+        this.awsJobEnabled = awsJobEnabled;
+        this.reportPattern = this.awsJobEnabled ? Pattern.compile(REGEX) : Pattern.compile(".*" + REPORT_SUFIX + "$");
+    }
+
+    /**
+     * Return the list of files for new reports.
+     *
+     * @param s3Client the S3 client.
+     * @return the list of files.
+     * @throws AdapterException
+     */
+    public List<String> getFiles(AmazonS3 s3Client) throws AdapterException {
+        final List<S3ObjectSummary> objectSummaries = reportFilesInBillingBucket(s3Client);
+        return awsJobEnabled ? lastFilesPerBillingPeriod(objectSummaries) :
+                objectSummaries.stream().map(S3ObjectSummary::getKey).sorted().collect(toList());
+    }
+
+    private List<S3ObjectSummary> reportFilesInBillingBucket(AmazonS3 s3Client) throws AdapterException {
+        ListObjectsV2Request request = new ListObjectsV2Request()
+                .withBucketName(bucket);
+        ListObjectsV2Result result;
+        List<S3ObjectSummary> objectSummaries = new ArrayList<>();
+        try {
+            do {
+                result = s3Client.listObjectsV2(request);
+                objectSummaries.addAll(notProcessedFiles(result));
+            } while (result.isTruncated());
+        } catch (Exception e) {
+            throw new AdapterException("Cannot get the file listing of bucket \"" + bucket + "*\". " +
+                    e.getLocalizedMessage(), e);
+        }
+        return objectSummaries;
+    }
+
+    private List<S3ObjectSummary> notProcessedFiles(ListObjectsV2Result result) {
+        return result.getObjectSummaries()
+                .stream()
+                .filter(this::matchBillingRegexAndWasNotProcessed)
+                .collect(toList());
+    }
+
+    private boolean matchBillingRegexAndWasNotProcessed(S3ObjectSummary o) {
+        return reportPattern.matcher(o.getKey()).matches()
+                && !moduleData.wasProcessed(o.getKey(), o.getLastModified(),
+                extractDatePrefix(reportPattern, o));
+    }
+
+    /**
+     * Returns list of files that per billing period
+     * For particular billing period file with the biggest modification date will be returned
+     *
+     * @param objectSummaries amazon s3 objects
+     * @return list of file names
+     */
+    protected List<String> lastFilesPerBillingPeriod(List<S3ObjectSummary> objectSummaries) {
+        final Map<String, List<S3ObjectSummary>> months = objectSummaries.stream()
+                .collect(Collectors.groupingBy(o -> extractDatePrefix(reportPattern, o), mapping(o -> o, toList())));
+
+        return months.entrySet()
+                .stream()
+                .flatMap(this::lastFileForBillingPeriod)
+                .sorted()
+                .collect(Collectors.toList());
+    }
+
+    private Stream<? extends String> lastFileForBillingPeriod(Map.Entry<String, List<S3ObjectSummary>> entry) {
+        final List<S3ObjectSummary> assemblyIds = entry.getValue();
+        final S3ObjectSummary lastBillingFile = assemblyIds.stream()
+                .max(Comparator.comparing(S3ObjectSummary::getLastModified))
+                .orElseThrow(() -> new IllegalStateException("AssemblyId does not contains any file"));
+        return assemblyIds.stream()
+                .filter(s -> s.getKey().startsWith(StringUtils.substringBeforeLast(lastBillingFile.getKey(), "/")))
+                .map(S3ObjectSummary::getKey);
+    }
+
+    private String extractDatePrefix(Pattern pattern, S3ObjectSummary o) {
+        final String key = o.getKey();
+        final Matcher matcher = pattern.matcher(key);
+        if (matcher.find() && awsJobEnabled) {
+            return matcher.group(1);
+        } else {
+            return key;
+        }
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/mongo/AdapterMongoDb.java b/services/billing-aws/src/main/java/com/epam/datalab/mongo/AdapterMongoDb.java
new file mode 100644
index 0000000..38c5890
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/mongo/AdapterMongoDb.java
@@ -0,0 +1,229 @@
+/*
+ * 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.datalab.mongo;
+
+import com.epam.datalab.core.DBAdapterBase;
+import com.epam.datalab.core.aggregate.UsageDataList;
+import com.epam.datalab.exceptions.AdapterException;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.exceptions.ParseException;
+import com.epam.datalab.model.aws.ReportLine;
+import com.epam.datalab.module.ModuleName;
+import com.fasterxml.jackson.annotation.JsonClassDescription;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.model.UpdateOptions;
+import org.bson.Document;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.epam.datalab.mongo.MongoConstants.COLLECTION_SETTINGS;
+import static com.epam.datalab.mongo.MongoConstants.FIELD_SERIVICE_BASE_NAME;
+import static com.mongodb.client.model.Filters.eq;
+
+/**
+ * The adapter for file system.
+ */
+@JsonTypeName(ModuleName.ADAPTER_MONGO_DATALAB)
+@JsonClassDescription(
+        "Mongo DB adapter.\n" +
+                "Write converted data to the Mongo database. Can be used for AdapterOut only.\n" +
+                "  - type: " + ModuleName.ADAPTER_MONGO_DATALAB + "\n" +
+                "    host: <host>             - the host name or IP address.\n" +
+                "    port: <port>             - the port number.\n" +
+                "    database: <database>     - the name of database.\n" +
+                "    username: <username>     - the name of user.\n" +
+                "    password: <password>     - the password of user.\n" +
+                "    [bufferSize: <number>]   - the size of buffer, default is 10000 records.\n" +
+                "    [upsert: <false | true>] - if true then upsert is enabled."
+)
+public class AdapterMongoDb extends DBAdapterBase {
+
+    /**
+     * The size of buffer for bulk insert. Not applicable for upsert mode.
+     */
+    @JsonProperty
+    private int bufferSize = 10000;
+
+    /**
+     * The upsert mode if set to <b>true</b>.
+     */
+    @JsonProperty
+    private boolean upsert = false;
+
+    @JsonProperty
+    private String serviceBaseName;
+    /**
+     * Custom connection to Mongo database.
+     */
+    private MongoDbConnection connection;
+    /**
+     * Mongo collection.
+     */
+    private MongoCollection<Document> collection;
+    /**
+     * DAO of DataLab's resource type.
+     */
+    private DatalabResourceTypeDAO resourceTypeDAO;
+    /**
+     * Buffer for insert operations.
+     */
+    private List<Document> buffer;
+    /**
+     * List of dates for delete from MongoDB.
+     */
+    private UsageDataList usageDateList;
+
+    public String getServiceBaseName() {
+        return serviceBaseName;
+    }
+
+    public void setServiceBaseName(String serviceBaseName) {
+        this.serviceBaseName = serviceBaseName;
+    }
+
+    /**
+     * Return the size of buffer for bulk insert.
+     */
+    public int getBufferSize() {
+        return bufferSize;
+    }
+
+    /**
+     * Set the size of buffer for bulk insert.
+     *
+     * @throws InitializationException
+     */
+    public void setBufferSize(int bufferSize) throws InitializationException {
+        if (upsert && bufferSize <= 0) {
+            throw new InitializationException("The bufferSize must be greater than zero when upsert mode is switched" +
+                    " " +
+                    "on");
+        }
+        this.bufferSize = bufferSize;
+    }
+
+    /**
+     * Return the <b>true</b> if upsert mode switched on.
+     */
+    public boolean isUpsert() {
+        return upsert;
+    }
+
+    /**
+     * Set the upsert mode.
+     *
+     * @throws InitializationException
+     */
+    public void setUpsert(boolean upsert) throws InitializationException {
+        if (upsert && bufferSize <= 0) {
+            throw new InitializationException("Upsert mode cannot be enabled if the bufferSize is zero or less than " +
+                    "zero");
+        }
+        this.upsert = upsert;
+    }
+
+    @Override
+    public void open() throws AdapterException {
+        if (connection == null) {
+            if (getMode() != Mode.WRITE) {
+                throw new AdapterException("Mode of " + getType() + " adapter may be " + Mode.WRITE + " only.");
+            }
+            connection = new MongoDbConnection(getHost(), getPort(), getDatabase(), getUsername(), getPassword());
+            setServiceBaseName();
+            collection = connection.getCollection(MongoConstants.COLLECTION_BILLING);
+            try {
+                resourceTypeDAO = new DatalabResourceTypeDAO(connection);
+            } catch (InitializationException e) {
+                throw new AdapterException("Cannot initialize billing transformer to DataLab format. " + e.getLocalizedMessage(), e);
+            }
+
+            connection.createBillingIndexes();
+            usageDateList = new UsageDataList();
+            buffer = (upsert || bufferSize > 0 ? new ArrayList<>(bufferSize) : null);
+        } else {
+            throw new AdapterException("Connection is already opened");
+        }
+    }
+
+    private void setServiceBaseName() {
+        connection.getCollection(COLLECTION_SETTINGS)
+                .updateOne(eq("_id", FIELD_SERIVICE_BASE_NAME), new Document("$set", new Document("value", serviceBaseName)),
+                        new UpdateOptions().upsert(true));
+    }
+
+    @Override
+    public void close() throws AdapterException {
+        if (connection != null) {
+            if (upsert) {
+                connection.upsertRows(collection, buffer, usageDateList);
+            } else if (bufferSize > 0) {
+                connection.insertRows(collection, buffer);
+            }
+            buffer = null;
+
+            try {
+                connection.close();
+            } catch (Exception e) {
+                throw new AdapterException("Cannot close connection to database " +
+                        getDatabase() + ". " + e.getLocalizedMessage(), e);
+            } finally {
+                connection = null;
+            }
+        }
+    }
+
+    @Override
+    public String getEntryName() {
+        return MongoConstants.COLLECTION_BILLING;
+    }
+
+    @Override
+    public String readLine() throws AdapterException {
+        throw new AdapterException("Unimplemented method called.");
+    }
+
+    @Override
+    public void writeHeader(List<String> header) {
+        // Nothing to do
+    }
+
+    @Override
+    public Document writeRow(ReportLine row) throws AdapterException {
+        Document document;
+        try {
+            document = resourceTypeDAO.transform(row);
+        } catch (ParseException e) {
+            throw new AdapterException("Cannot transform report line. " + e.getLocalizedMessage(), e);
+        }
+
+        return document;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("bufferSize", bufferSize)
+                .add("upsert", upsert);
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/mongo/DatalabResourceTypeDAO.java b/services/billing-aws/src/main/java/com/epam/datalab/mongo/DatalabResourceTypeDAO.java
new file mode 100644
index 0000000..e407804
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/mongo/DatalabResourceTypeDAO.java
@@ -0,0 +1,115 @@
+/*
+ * 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.datalab.mongo;
+
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.exceptions.ParseException;
+import com.epam.datalab.model.aws.ReportLine;
+import org.bson.Document;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.mongodb.client.model.Filters.eq;
+import static org.apache.commons.lang3.StringUtils.EMPTY;
+
+/**
+ * Provides Mongo DAO for billing resources in DataLab.
+ */
+public class DatalabResourceTypeDAO implements MongoConstants {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DatalabResourceTypeDAO.class);
+
+    /**
+     * Mongo database connection.
+     */
+    private final MongoDbConnection connection;
+
+    /**
+     * Service base name.
+     */
+    private String serviceBaseName;
+    private String serviceBaseNameId;
+
+    /**
+     * Instantiate DAO for billing resources.
+     *
+     * @param connection the connection to Mongo DB.
+     * @throws InitializationException
+     */
+    public DatalabResourceTypeDAO(MongoDbConnection connection) throws InitializationException {
+        this.connection = connection;
+        setServiceBaseName();
+    }
+
+    /**
+     * Returns the base name of service.
+     */
+    public String getServiceBaseName() {
+        return serviceBaseName;
+    }
+
+    /**
+     * Set the base name of service.
+     *
+     * @throws InitializationException
+     */
+    private void setServiceBaseName() throws InitializationException {
+        Document d = connection.getCollection(COLLECTION_SETTINGS)
+                .find(eq(FIELD_ID, FIELD_SERIVICE_BASE_NAME))
+                .first();
+        if (d == null) {
+            throw new InitializationException("Service base name property " + COLLECTION_SETTINGS +
+                    "." + FIELD_SERIVICE_BASE_NAME + " in Mongo DB not found");
+        }
+        String value = d.getOrDefault("value", EMPTY).toString();
+        if (d.isEmpty()) {
+            throw new InitializationException("Service base name property " + COLLECTION_SETTINGS +
+                    "." + FIELD_SERIVICE_BASE_NAME + " in Mongo DB is empty");
+        }
+        serviceBaseName = value;
+        serviceBaseNameId = value + ":";
+        LOGGER.debug("serviceBaseName is {}", serviceBaseName);
+    }
+
+    /**
+     * Convert and return the report line of billing to Mongo document.
+     *
+     * @param row report line.
+     * @return Mongo document.
+     * @throws ParseException
+     */
+    public Document transform(ReportLine row) throws ParseException {
+        String resourceId = row.getDatalabId();
+        if (resourceId == null || !resourceId.startsWith(serviceBaseNameId)) {
+            throw new ParseException("DatalabId is not match: expected start with " + serviceBaseNameId + ", actual " +
+                    resourceId);
+        }
+        resourceId = resourceId.substring(serviceBaseNameId.length());
+        Document d = new Document(ReportLine.FIELD_DATALAB_ID, resourceId);
+        return d.append(ReportLine.FIELD_USAGE_DATE, row.getUsageDate())
+                .append(ReportLine.FIELD_PRODUCT, row.getProduct())
+                .append(ReportLine.FIELD_USAGE_TYPE, row.getUsageType())
+                .append(ReportLine.FIELD_USAGE, row.getUsage())
+                .append(ReportLine.FIELD_COST, row.getCost())
+                .append(ReportLine.FIELD_CURRENCY_CODE, row.getCurrencyCode())
+                .append(ReportLine.FIELD_RESOURCE_TYPE, row.getResourceType().category())
+                .append(ReportLine.FIELD_RESOURCE_ID, row.getResourceId())
+                .append(ReportLine.FIELD_TAGS, row.getTags());
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/mongo/MongoConstants.java b/services/billing-aws/src/main/java/com/epam/datalab/mongo/MongoConstants.java
new file mode 100644
index 0000000..d93217a
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/mongo/MongoConstants.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.datalab.mongo;
+
+/**
+ * The constants names of collections and fields in Mongo DB.
+ */
+public interface MongoConstants {
+    String FIELD_ID = "_id";
+    String COLLECTION_SETTINGS = "settings";
+    String FIELD_SERIVICE_BASE_NAME = "conf_service_base_name";
+    String FIELD_EXPLORATORY_NAME = "exploratory_name";
+    String COLLECTION_BILLING = "billing";
+    String BILLING_DATA_COLLECTION = "BillingData";
+}
diff --git a/services/billing-aws/src/main/java/com/epam/datalab/mongo/MongoDbConnection.java b/services/billing-aws/src/main/java/com/epam/datalab/mongo/MongoDbConnection.java
new file mode 100644
index 0000000..a9993b5
--- /dev/null
+++ b/services/billing-aws/src/main/java/com/epam/datalab/mongo/MongoDbConnection.java
@@ -0,0 +1,223 @@
+/*
+ * 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.datalab.mongo;
+
+import com.epam.datalab.core.aggregate.UsageDataList;
+import com.epam.datalab.exceptions.AdapterException;
+import com.epam.datalab.model.aws.ReportLine;
+import com.mongodb.BasicDBObject;
+import com.mongodb.MongoClient;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
+import com.mongodb.WriteConcern;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
+import com.mongodb.client.model.IndexOptions;
+import com.mongodb.client.result.DeleteResult;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+import static com.mongodb.client.model.Filters.eq;
+
+/**
+ * Provides operation with Mongo database and billing report.
+ */
+public class MongoDbConnection implements Closeable {
+    private static final Logger LOGGER = LoggerFactory.getLogger(MongoDbConnection.class);
+
+    /**
+     * Mongo client.
+     */
+    private MongoClient client;
+
+    /**
+     * Mongo database.
+     */
+    private MongoDatabase database;
+
+
+    /**
+     * Instantiate the helper for Mongo database adapter.
+     *
+     * @param host         the host name.
+     * @param port         the port.
+     * @param databaseName the name of database.
+     * @param username     the name of user.
+     * @param password     the password.
+     * @throws AdapterException
+     */
+    public MongoDbConnection(String host, int port, String databaseName, String username, String password) throws
+            AdapterException {
+        try {
+            client = new MongoClient(
+                    new ServerAddress(host, port),
+                    Collections.singletonList(
+                            MongoCredential.createCredential(username, databaseName, password.toCharArray())));
+            database = client.getDatabase(databaseName).withWriteConcern(WriteConcern.ACKNOWLEDGED);
+        } catch (Exception e) {
+            throw new AdapterException("Cannot create connection to database " +
+                    databaseName + ". " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Close connection to Mongo database.
+     */
+    @Override
+    public void close() throws IOException {
+        if (client != null) {
+            try {
+                client.close();
+            } catch (Exception e) {
+                throw new IOException(e.getLocalizedMessage(), e);
+            } finally {
+                client = null;
+                database = null;
+            }
+        }
+    }
+
+    /**
+     * Create index on billing collection.
+     *
+     * @param indexName the name of index.
+     * @param index     the index options.
+     */
+    private void createBillingIndexes(String indexName, Bson index) {
+        MongoCollection<Document> collection = database.getCollection(MongoConstants.COLLECTION_BILLING);
+        IndexOptions options = new IndexOptions().name(MongoConstants.COLLECTION_BILLING + indexName);
+        try {
+            collection
+                    .createIndex(index, options);
+        } catch (Exception e) {
+            LOGGER.warn("Cannot create index {} on collection {}. {}", options.getName(),
+                    MongoConstants.COLLECTION_BILLING, e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Create index on Mongo collection for fast upsert operations.
+     */
+    public void createBillingIndexes() {
+        createBillingIndexes("_IntervalIdx",
+                new BasicDBObject()
+                        .append(ReportLine.FIELD_USER_ID, 1)
+                        .append(ReportLine.FIELD_USAGE_DATE, 2));
+        createBillingIndexes("_ExploratoryIdx",
+                new BasicDBObject()
+                        .append(ReportLine.FIELD_USER_ID, 1)
+                        .append(MongoConstants.FIELD_EXPLORATORY_NAME, 2));
+    }
+
+    /**
+     * Return the collection of Mongo database.
+     *
+     * @param collectionName the name of collection.
+     */
+    public MongoCollection<Document> getCollection(String collectionName) {
+        return database.getCollection(collectionName);
+    }
+
+    /**
+     * Insert document to Mongo.
+     *
+     * @param collection the name of collection.
+     * @param document   the document.
+     * @throws AdapterException
+     */
+    public void insertOne(MongoCollection<Document> collection, Document document) throws AdapterException {
+        try {
+            collection.insertOne(document);
+        } catch (Exception e) {
+            throw new AdapterException("Cannot insert document into collection " +
+                    collection.getNamespace() + ": " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Insert documents from list to Mongo collection and clear list.
+     *
+     * @param collection Mongo collection.
+     * @param documents  the list of documents.
+     * @throws AdapterException
+     */
+    public void insertRows(MongoCollection<Document> collection, List<Document> documents) throws AdapterException {
+        try {
+            if (!documents.isEmpty()) {
+                collection.insertMany(documents);
+                LOGGER.debug("{} documents has been inserted into collection {}",
+                        documents.size(), collection.getNamespace());
+                documents.clear();
+            }
+        } catch (Exception e) {
+            throw new AdapterException("Cannot insert new documents into collection " +
+                    collection.getNamespace() + ": " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Insert documents from list to Mongo collection and clear list.
+     *
+     * @param collection    Mongo collection.
+     * @param documents     the list of documents.
+     * @param usageDateList list of the data interval to deletion old data from Mongo.
+     * @throws AdapterException
+     */
+    public void upsertRows(MongoCollection<Document> collection, List<Document> documents, UsageDataList usageDateList)
+            throws AdapterException {
+        deleteRows(collection, usageDateList);
+        insertRows(collection, documents);
+    }
+
+    /**
+     * Delete the documents from Mongo collection.
+     *
+     * @param collection    Mongo collection.
+     * @param usageDateList list of the data interval to deletion data from Mongo.
+     * @throws AdapterException
+     */
+    public void deleteRows(MongoCollection<Document> collection, UsageDataList usageDateList)
+            throws AdapterException {
+        try {
+            long rowCount = 0;
+            for (String date : usageDateList) {
+                if (!usageDateList.get(date)) {
+                    DeleteResult result = collection.deleteMany(eq(ReportLine.FIELD_USAGE_DATE, date));
+                    rowCount += result.getDeletedCount();
+                    usageDateList.set(date, true);
+                }
+            }
+            if (rowCount > 0) {
+                LOGGER.debug("{} documents has been deleted from collection {}",
+                        rowCount, collection.getNamespace());
+            }
+        } catch (Exception e) {
+            throw new AdapterException("Cannot delete old rows from collection " +
+                    collection.getNamespace() + ": " + e.getLocalizedMessage(), e);
+        }
+    }
+}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/BillingAwsApplication.java b/services/billing-aws/src/main/java/com/epam/dlab/BillingAwsApplication.java
deleted file mode 100644
index c878370..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/BillingAwsApplication.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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;
-
-import com.epam.dlab.exceptions.InitializationException;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
-
-@SpringBootApplication
-@EnableMongoRepositories
-@EnableConfigurationProperties
-public class BillingAwsApplication {
-
-    public static void main(String[] args) throws InitializationException {
-        SpringApplication.run(BillingAwsApplication.class, args);
-        BillingServiceImpl.startApplication(args);
-    }
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/BillingService.java b/services/billing-aws/src/main/java/com/epam/dlab/BillingService.java
deleted file mode 100644
index 15dcc32..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/BillingService.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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;
-
-import com.epam.dlab.dto.billing.BillingData;
-
-import java.util.List;
-
-@FunctionalInterface
-public interface BillingService {
-    List<BillingData> getBillingData();
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/BillingServiceImpl.java b/services/billing-aws/src/main/java/com/epam/dlab/BillingServiceImpl.java
deleted file mode 100644
index 393a1be..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/BillingServiceImpl.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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;
-
-import com.epam.dlab.configuration.BillingToolConfiguration;
-import com.epam.dlab.configuration.BillingToolConfigurationFactory;
-import com.epam.dlab.core.parser.ParserBase;
-import com.epam.dlab.dto.billing.BillingData;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.util.ServiceUtils;
-import org.bson.Document;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-
-import java.time.LocalDate;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.model.aws.ReportLine.FIELD_COST;
-import static com.epam.dlab.model.aws.ReportLine.FIELD_CURRENCY_CODE;
-import static com.epam.dlab.model.aws.ReportLine.FIELD_DLAB_ID;
-import static com.epam.dlab.model.aws.ReportLine.FIELD_PRODUCT;
-import static com.epam.dlab.model.aws.ReportLine.FIELD_RESOURCE_TYPE;
-import static com.epam.dlab.model.aws.ReportLine.FIELD_USAGE_DATE;
-
-@Service
-public class BillingServiceImpl implements BillingService {
-	private static final Logger LOGGER = LoggerFactory.getLogger(BillingServiceImpl.class);
-	private static BillingToolConfiguration configuration;
-
-	public List<BillingData> getBillingData() {
-		try {
-			ParserBase parser = configuration.build();
-
-			List<BillingData> billingData = parser.parse()
-					.stream()
-					.map(this::toBillingData)
-					.collect(Collectors.toList());
-
-			if (!parser.getStatistics().isEmpty()) {
-				LOGGER.info("Billing report parser statistics:");
-				for (int i = 0; i < parser.getStatistics().size(); i++) {
-					LOGGER.info("  {}", parser.getStatistics().get(i).toString());
-				}
-			}
-
-			return billingData;
-		} catch (Exception e) {
-			LOGGER.error("Something went wrong ", e);
-			return Collections.emptyList();
-		}
-	}
-
-	private BillingData toBillingData(Document billingData) {
-		return BillingData.builder()
-				.tag(billingData.getString(FIELD_DLAB_ID).toLowerCase())
-				.usageDateFrom(Optional.ofNullable(billingData.getString(FIELD_USAGE_DATE)).map(LocalDate::parse).orElse(null))
-				.usageDateTo(Optional.ofNullable(billingData.getString(FIELD_USAGE_DATE)).map(LocalDate::parse).orElse(null))
-				.usageDate(billingData.getString(FIELD_USAGE_DATE))
-				.product(billingData.getString(FIELD_PRODUCT))
-				.usageType(billingData.getString(FIELD_RESOURCE_TYPE))
-				.cost(billingData.getDouble(FIELD_COST))
-				.currency(billingData.getString(FIELD_CURRENCY_CODE))
-				.build();
-	}
-
-	public static void initialize(String filename) throws InitializationException {
-		LOGGER.debug("Billing report configuration file: {}", filename);
-		configuration = BillingToolConfigurationFactory.build(filename, BillingToolConfiguration.class);
-	}
-
-	public static void startApplication(String[] args) throws InitializationException {
-		if (ServiceUtils.printAppVersion(BillingTool.class, args)) {
-			return;
-		}
-
-		String confName = null;
-		for (int i = 0; i < args.length; i++) {
-			if (BillingTool.isKey("help", args[i])) {
-				i++;
-				Help.usage(i < args.length ? Arrays.copyOfRange(args, i, args.length) : null);
-				return;
-			} else if (BillingTool.isKey("conf", args[i])) {
-				i++;
-				if (i < args.length) {
-					confName = args[i];
-				} else {
-					throw new InitializationException("Missing the name of configuration file");
-				}
-			}
-		}
-
-		if (confName == null) {
-			Help.usage();
-			throw new InitializationException("Missing arguments");
-		}
-
-		BillingTool.setLoggerLevel();
-		try {
-			initialize(confName);
-		} catch (Exception e) {
-			throw new DlabException("Billing scheduler failed", e);
-		}
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/BillingTool.java b/services/billing-aws/src/main/java/com/epam/dlab/BillingTool.java
deleted file mode 100644
index b7791ad..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/BillingTool.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * 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;
-
-import ch.qos.logback.classic.Level;
-import ch.qos.logback.classic.LoggerContext;
-import com.epam.dlab.configuration.BillingToolConfiguration;
-import com.epam.dlab.configuration.BillingToolConfigurationFactory;
-import com.epam.dlab.core.parser.ParserBase;
-import com.epam.dlab.exceptions.AdapterException;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.exceptions.ParseException;
-import com.epam.dlab.util.ServiceUtils;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Arrays;
-
-/** Provides billing parser features.
- */
-public class BillingTool {
-	private static final Logger LOGGER = LoggerFactory.getLogger(BillingTool.class);
-	
-	/** Runs parser for given configuration.
-	 * @param conf billing configuration.
-	 * @throws InitializationException
-	 * @throws AdapterException
-	 * @throws ParseException
-	 */
-	public void run(BillingToolConfiguration conf) throws InitializationException, AdapterException, ParseException {
-		ParserBase parser = conf.build();
-		LOGGER.debug("Billing Tool Configuration: {}", conf);
-		LOGGER.debug("Parser configuration: {}", parser);
-		
-		parser.parse();
-		LOGGER.debug("Billing Tool statistics: {}", parser.getStatistics());
-	}
-	
-	/** Runs parser for given configuration in file.
-	 * @param filename the name of file for billing configuration.
-	 * @throws InitializationException
-	 * @throws AdapterException
-	 * @throws ParseException
-	 */
-	public void run(String filename) throws InitializationException, AdapterException, ParseException {
-		run(BillingToolConfigurationFactory.build(filename, BillingToolConfiguration.class));
-	}
-	
-	/** Runs parser for given configuration.
-	 * @param jsonNode the billing configuration.
-	 * @throws InitializationException
-	 * @throws AdapterException
-	 * @throws ParseException
-	 */
-	public void run(JsonNode jsonNode) throws InitializationException, AdapterException, ParseException {
-		run(BillingToolConfigurationFactory.build(jsonNode, BillingToolConfiguration.class));
-	}
-	
-	
-	/** Check the key name for command line.
-	 * @param keyName the name of key.
-	 * @param arg the argument from command line.
-	 * @return <b>true</b> if given argument is key.
-	 */
-	protected static boolean isKey(String keyName, String arg) {
-		return (("--" + keyName).equalsIgnoreCase(arg) ||
-				("/" + keyName).equalsIgnoreCase(arg));
-	}
-	
-	/** Set the level of loggers to INFO for external loggers.
-	 */
-	protected static void setLoggerLevel() {
-		ch.qos.logback.classic.LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
-		ch.qos.logback.classic.Logger logger;
-		String[] loggers = {
-				"org.hibernate",
-				"org.jboss.logging"
-		};
-		for (String name : loggers) {
-			logger = context.getLogger(name);
-			logger.setLevel(Level.INFO);
-		}
-	}
-	
-	
-	/** Runs parser for given configuration.
-	 * @param args the arguments of command line. 
-	 * @throws InitializationException
-	 */
-	public static void main(String[] args) throws InitializationException {
-		if (ServiceUtils.printAppVersion(BillingServiceImpl.class, args)) {
-			return;
-		}
-
-		String confName = null;
-		String json = null;
-
-		for (int i = 0; i < args.length; i++) {
-			if (isKey("help", args[i])) {
-				i++;
-				Help.usage(i < args.length ? Arrays.copyOfRange(args, i, args.length) : null);
-				return;
-			} else if (isKey("conf", args[i])) {
-				i++;
-				if (i < args.length) {
-					confName = args[i];
-				} else {
-					throw new InitializationException("Missing the name of configuration file");
-				}
-			} else if (isKey("json", args[i])) {
-				i++;
-				if (i < args.length) {
-					json = args[i];
-				} else {
-					throw new InitializationException("Missing the content of json configuration");
-				}
-			} else {
-				throw new InitializationException("Unknow argument: " + args[i]);
-			}
-		}
-
-		if (confName == null && json == null) {
-			Help.usage();
-			throw new InitializationException("Missing arguments");
-		}
-		
-		if (confName != null && json != null) {
-			Help.usage();
-			throw new InitializationException("Invalid arguments.");
-		}
-
-		setLoggerLevel();
-		try {
-			if (confName != null) {
-				new BillingTool().run(confName);
-			} else {
-				JsonNode jsonNode = new ObjectMapper().valueToTree(json);
-				new BillingTool().run(jsonNode);
-			}
-		} catch (Exception e) {
-			throw new DlabException("Billing tool failed", e);
-		}
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/Help.java b/services/billing-aws/src/main/java/com/epam/dlab/Help.java
deleted file mode 100644
index 579afc1..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/Help.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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;
-
-import com.epam.dlab.core.BillingUtils;
-import com.epam.dlab.core.ModuleType;
-import com.epam.dlab.exceptions.InitializationException;
-import com.fasterxml.jackson.annotation.JsonClassDescription;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/** Print help for billing tool.
- */
-public class Help {
-
-	private Help() {
-	}
-
-	/** Print help to console.
-	 * @param resourceName the name of resource.
-	 * @param substitute - map for substitution in help content.
-	 * @throws InitializationException
-	 */
-	private static void printHelp(String resourceName, Map<String, String> substitute) throws InitializationException {
-		List<String> list = BillingUtils.getResourceAsList("/" + Help.class.getName() + "." + resourceName + ".txt");
-		String help = StringUtils.join(list, System.lineSeparator());
-
-		if (substitute == null) {
-			substitute = new HashMap<>();
-		}
-		substitute.put("classname", BillingServiceImpl.class.getName());
-
-		for (String key : substitute.keySet()) {
-			help = StringUtils.replace(help, "${" + key.toUpperCase() + "}", substitute.get(key));
-		}
-		System.out.println(help);
-	}
-
-	/** Create and return substitutions for names of modules.
-	 * @return
-	 * @throws InitializationException
-	 */
-	private static Map<String, String> findModules() throws InitializationException {
-		List<Class<?>> modules = BillingUtils.getModuleClassList();
-		Map<String, String> substitute = new HashMap<>();
-		
-		for (Class<?> module : modules) {
-			ModuleType type = BillingUtils.getModuleType(module);
-			JsonTypeName typeName = module.getAnnotation(JsonTypeName.class);
-			if (typeName != null) {
-				String typeNames = substitute.get(type.toString() + "s");
-				typeNames = (typeNames == null ? typeName.value() : typeNames + ", " + typeName.value());
-				substitute.put(type.toString() + "s", typeNames);
-			}
-		}
-		
-		return substitute;
-	}
-
-	/** Find and return help for module.
-	 * @param type the type of module.
-	 * @param name the name of module.
-	 * @throws InitializationException
-	 */
-	private static String findModuleHelp(ModuleType type, String name) throws InitializationException {
-		List<Class<?>> modules = BillingUtils.getModuleClassList();
-		String typeNames = null;
-		for (Class<?> module : modules) {
-			ModuleType t = BillingUtils.getModuleType(module);
-			if (t == type) {
-				JsonTypeName typeName = module.getAnnotation(JsonTypeName.class);
-				if (typeName != null ) {
-					if (name.equals(typeName.value())) {
-						JsonClassDescription description = module.getAnnotation(JsonClassDescription.class);
-						if (description != null) {
-							return description.value();
-						}
-						throw new InitializationException("Help for " + type + " " + name + " not found");
-					} else {
-						typeNames = (typeNames == null ? typeName.value() : typeNames + ", " + typeName.value());
-					}
-				}
-			}
-		}
-		throw new InitializationException("Module for " + type + " " + name + " not found." +
-				(typeNames == null ? "" : " Module type must be one of next: " + typeNames));
-	}
-
-	/** Print help screen for billing tool. 
-	 * @throws InitializationException */
-	public static void usage(String ... args) throws InitializationException {
-		if (args == null || args.length == 0) {
-			printHelp("usage", null);
-		} else if ("conf".equalsIgnoreCase(args[0])) {
-			printHelp("conf", findModules());
-		} else {
-			ModuleType type = ModuleType.of(args[0]);
-			if (type == null) {
-				System.out.println("Unknown --help " + args[0] + " command.");
-			} else if (args.length < 2) {
-				System.out.println("Missing the type of module.");
-				String typeNames = findModules().get(type.toString() + "s");
-				if (typeNames != null) {
-					System.out.println("Must be one of next: " + typeNames);
-				}
-			} else if (args.length > 2) {
-				System.out.println("Extra arguments in command: " +
-					StringUtils.join(Arrays.copyOfRange(args, 2, args.length), " "));
-			} else {
-				System.out.println(findModuleHelp(type, args[1]));
-			}
-		}
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/conf/SecurityConfig.java b/services/billing-aws/src/main/java/com/epam/dlab/conf/SecurityConfig.java
deleted file mode 100644
index 2e10810..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/conf/SecurityConfig.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.conf;
-
-import org.keycloak.adapters.KeycloakConfigResolver;
-import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
-import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
-import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
-import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
-import org.springframework.security.core.session.SessionRegistryImpl;
-import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
-import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
-
-@KeycloakConfiguration
-class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
-
-    @Autowired
-    public void configureGlobal(AuthenticationManagerBuilder auth) {
-        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
-        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
-        auth.authenticationProvider(keycloakAuthenticationProvider);
-    }
-
-    @Bean
-    public KeycloakConfigResolver keycloakConfigResolver() {
-        return new KeycloakSpringBootConfigResolver();
-    }
-
-    @Bean
-    @Override
-    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
-        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
-    }
-
-    @Override
-    protected void configure(HttpSecurity http) throws Exception {
-        super.configure(http);
-        http
-                .anonymous().disable()
-                .authorizeRequests()
-                .anyRequest()
-                .authenticated();
-    }
-}
\ No newline at end of file
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/configuration/BillingToolConfiguration.java b/services/billing-aws/src/main/java/com/epam/dlab/configuration/BillingToolConfiguration.java
deleted file mode 100644
index ae79f86..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/configuration/BillingToolConfiguration.java
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * 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.configuration;
-
-import com.epam.dlab.BillingTool;
-import com.epam.dlab.core.AdapterBase;
-import com.epam.dlab.core.AdapterBase.Mode;
-import com.epam.dlab.core.FilterBase;
-import com.epam.dlab.core.ModuleBase;
-import com.epam.dlab.core.ModuleData;
-import com.epam.dlab.core.parser.ParserBase;
-import com.epam.dlab.exceptions.AdapterException;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.mongo.MongoDbConnection;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import com.google.common.collect.ImmutableList;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-
-/**
- * Describe configuration for {@link BillingTool}
- */
-public class BillingToolConfiguration {
-
-	/**
-	 * The host name.
-	 */
-	@JsonProperty
-	private String host;
-
-	/**
-	 * The port.
-	 */
-	@JsonProperty
-	private int port;
-
-	/**
-	 * The name of database.
-	 */
-	@JsonProperty
-	private String database;
-
-	/**
-	 * The name of user.
-	 */
-	@JsonProperty
-	private String username;
-
-	/**
-	 * The password.
-	 */
-	@JsonProperty
-	private String password;
-
-	@JsonProperty
-	private boolean billingEnabled;
-
-	/**
-	 * Adapter for reading source data.
-	 */
-	@Valid
-	@NotNull
-	@JsonProperty
-	private ImmutableList<AdapterBase> adapterIn;
-
-	/**
-	 * Adapter for writing converted data.
-	 */
-	@Valid
-	@NotNull
-	@JsonProperty
-	private ImmutableList<AdapterBase> adapterOut;
-
-	/**
-	 * Parser of source data to common format.
-	 */
-	@Valid
-	@NotNull
-	@JsonProperty
-	private ImmutableList<ParserBase> parser;
-
-	/**
-	 * Filter for source and converted data.
-	 */
-	@Valid
-	@JsonProperty
-	private ImmutableList<FilterBase> filter = null;
-
-	/**
-	 * Logging configuration.
-	 */
-	@Valid
-	@JsonProperty
-	private LoggingConfigurationFactory logging = null;
-
-
-	/**
-	 * Working data of modules.
-	 */
-	@JsonIgnore
-	private ModuleData moduleData;
-
-	/**
-	 * Return the adapter for reading source data.
-	 */
-	public ImmutableList<AdapterBase> getAdapterIn() {
-		return adapterIn;
-	}
-
-	/**
-	 * Set the adapter for reading source data.
-	 */
-	public void setAdapterIn(ImmutableList<AdapterBase> adapter) {
-		for (AdapterBase a : adapter) {
-			a.setMode(Mode.READ);
-		}
-		this.adapterIn = adapter;
-	}
-
-	/**
-	 * Return the adapter for writing converted data.
-	 */
-	public ImmutableList<AdapterBase> getAdapterOut() {
-		return adapterOut;
-	}
-
-	/**
-	 * Set the adapter for writing converted data.
-	 */
-	public void setAdapterOut(ImmutableList<AdapterBase> adapter) {
-		for (AdapterBase a : adapter) {
-			a.setMode(Mode.WRITE);
-		}
-		this.adapterOut = adapter;
-	}
-
-	/**
-	 * Return the parser of source data to common format.
-	 */
-	public ImmutableList<ParserBase> getParser() {
-		return parser;
-	}
-
-	/**
-	 * Set the parser of source data to common format.
-	 */
-	public void setParser(ImmutableList<ParserBase> parser) {
-		this.parser = parser;
-	}
-
-	/**
-	 * Return the filter for source and converted data.
-	 */
-	public ImmutableList<FilterBase> getFilter() {
-		return filter;
-	}
-
-	/**
-	 * Set the filter for source and converted data.
-	 */
-	public void setFilter(ImmutableList<FilterBase> filter) {
-		this.filter = filter;
-	}
-
-	/**
-	 * Return the logging configuration.
-	 */
-	public LoggingConfigurationFactory getLogging() {
-		return logging;
-	}
-
-	/**
-	 * Set the logging configuration.
-	 */
-	public void setLogging(LoggingConfigurationFactory logging) {
-		this.logging = logging;
-	}
-
-
-	/**
-	 * Return the working data of modules.
-	 */
-	@JsonIgnore
-	public ModuleData getModuleData() {
-		return moduleData;
-	}
-
-	/**
-	 * Check and return module.
-	 *
-	 * @param modules    the list of modules.
-	 * @param name       the name of module.
-	 * @param isOptional optional module or not.
-	 * @return module
-	 * @throws InitializationException
-	 */
-	private <T extends ModuleBase> T getModule(ImmutableList<T> modules, String name, boolean isOptional) throws
-			InitializationException {
-		T module = (modules != null && modules.size() == 1 ? modules.get(0) : null);
-		if (!isOptional && module == null) {
-			throw new InitializationException("Invalid configuration for property " + name);
-		}
-		return module;
-	}
-
-	/**
-	 * Build and return the parser.
-	 *
-	 * @return the parser.
-	 * @throws InitializationException
-	 */
-	public ParserBase build() throws InitializationException {
-		ParserBase parserBase = getModule(this.parser, "parser", false);
-		AdapterBase in = getModule(adapterIn, "adapterIn", false);
-		AdapterBase out = getModule(adapterOut, "adapterOut", false);
-		FilterBase f = getModule(filter, "filter", true);
-
-		final MongoDbConnection connection;
-		try {
-			connection = new MongoDbConnection(host, port, database, username, password);
-		} catch (AdapterException e) {
-			throw new InitializationException("Cannot configure mongo connection. " + e.getLocalizedMessage(), e);
-		}
-		moduleData = new ModuleData(connection);
-
-		parserBase.setModuleData(moduleData);
-		in.setModuleData(moduleData);
-		out.setModuleData(moduleData);
-		if (f != null) {
-			f.setModuleData(moduleData);
-		}
-
-		return parserBase.build(in, out, f);
-	}
-
-	public boolean isBillingEnabled() {
-		return billingEnabled;
-	}
-
-	/**
-	 * Returns a string representation of the object.
-	 *
-	 * @param self the object to generate the string for (typically this), used only for its class name.
-	 */
-	public ToStringHelper toStringHelper(Object self) {
-		return MoreObjects.toStringHelper(self)
-				.add("moduleData", moduleData)
-				.add("adapterIn", adapterIn)
-				.add("adapterOut", adapterOut)
-				.add("filter", filter)
-				.add("parser", parser)
-				.add("logging", logging)
-				.add("billingEnabled", billingEnabled);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this)
-				.toString();
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/configuration/BillingToolConfigurationFactory.java b/services/billing-aws/src/main/java/com/epam/dlab/configuration/BillingToolConfigurationFactory.java
deleted file mode 100644
index 1de80af..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/configuration/BillingToolConfigurationFactory.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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.configuration;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import com.epam.dlab.core.BillingUtils;
-import com.epam.dlab.exceptions.InitializationException;
-import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
-import com.fasterxml.jackson.datatype.guava.GuavaModule;
-
-/** Build the instance of class {@link BillingToolConfiguration}. 
- */
-public class BillingToolConfigurationFactory {
-
-	/** Mapper for reading configuration. */
-	private static ObjectMapper mapper;
-	
-	/** Build the instance of class {@link BillingToolConfiguration} from YAML file.
-	 * @param filename the name of file.
-	 * @param confClass configuration class.
-	 * @return the instance of configuration.
-	 * @throws InitializationException
-	 */
-	public static <T extends BillingToolConfiguration> T build(String filename, Class<T> confClass) throws InitializationException {
-		try {
-			InputStream is = new FreeMarkerConfig().getInputStream(filename);
-			JsonNode node = getMapper().readTree(new YAMLFactory().createParser(is));
-			return build(node, confClass);
-		} catch (IOException | InitializationException e) {
-			throw new InitializationException("Cannot parse configuration file " + filename + ". " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/** Build the instance of class {@link BillingToolConfiguration} from YAML file.
-	 * @param node the content of configuration.
-	 * @param confClass configuration class.
-	 * @return the instance of configuration.
-	 * @throws InitializationException
-	 */
-	public static <T extends BillingToolConfiguration> T build(JsonNode node, Class<T> confClass) throws InitializationException {
-		T conf;
-		try {
-			conf = getMapper().readValue(node.toString(), confClass);
-		} catch (Exception e) {
-			throw new InitializationException("Cannot parse json configuration. " + e.getLocalizedMessage(), e);
-		}
-
-		try {
-			LoggingConfigurationFactory logging = conf.getLogging();
-			if (logging != null) {
-				logging.configure();
-			}
-		} catch (Exception e) {
-			throw new InitializationException("Cannot initialize configuration. " + e.getLocalizedMessage(), e);
-		}
-		
-		new ConfigurationValidator<T>()
-			.validate(conf);
-
-		return conf;
-	}
-	
-	/** Return the mapper for reading configuration. 
-	 * @throws InitializationException
-	 */
-	private static ObjectMapper getMapper() throws InitializationException {
-		if (mapper != null) {
-			return mapper;
-		}
-        mapper = new ObjectMapper()
-        		.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
-        mapper.registerModule(new GuavaModule());
-    	for (Class<?> clazz : BillingUtils.getModuleClassList()) {
-			mapper.registerSubtypes(clazz);
-		}
-        
-        return mapper;
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/configuration/ConfigJsonGenerator.java b/services/billing-aws/src/main/java/com/epam/dlab/configuration/ConfigJsonGenerator.java
deleted file mode 100644
index 0ed8a18..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/configuration/ConfigJsonGenerator.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.configuration;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import com.epam.dlab.core.BillingUtils;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-/** Generate the json configuration of billing tool.
- */
-public class ConfigJsonGenerator {
-
-	/** Buffer for configuration properties. */
-	private Map<String, Map<String, String>[]> config = new HashMap<>();
-	
-	/** Add the properties of module to configuration.
-	 * @param moduleName the name of module.
-	 * @param properties the properties: key and value sequence.
-	 */
-	private ConfigJsonGenerator withModule(String moduleName, String ... properties) {
-		if (properties == null) {
-			config.remove(moduleName);
-			return this;
-		}
-		
-		@SuppressWarnings("unchecked")
-		Map<String, String>[] map = new Map[1];
-		map[0] = BillingUtils.stringsToMap(properties);
-		config.put(moduleName, map);
-		return this;
-	}
-
-	/** Add the properties of input adapter to configuration.
-	 * @param properties the properties: key and value sequence.
-	 */
-	public ConfigJsonGenerator withAdapterIn(String ... properties) {
-		return withModule("adapterIn", properties);
-	}
-	
-	/** Add the properties of output adapter to configuration.
-	 * @param properties the properties: key and value sequence.
-	 */
-	public ConfigJsonGenerator withAdapterOut(String ... properties) {
-		return withModule("adapterOut", properties);
-	}
-	
-	/** Add the properties of parser to configuration.
-	 * @param properties the properties: key and value sequence.
-	 */
-	public ConfigJsonGenerator withParser(String ... properties) {
-		return withModule("parser", properties);
-	}
-	
-	/** Add the properties of filter to configuration.
-	 * @param properties the properties: key and value sequence.
-	 */
-	public ConfigJsonGenerator withFilter(String ... properties) {
-		return withModule("filter", properties);
-	}
-	
-	/** Build and return json configuration.
-	 * @param properties the properties: key and value sequence.
-	 */
-	public JsonNode build() {
-		return new ObjectMapper()
-				.valueToTree(config);
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/configuration/ConfigurationValidator.java b/services/billing-aws/src/main/java/com/epam/dlab/configuration/ConfigurationValidator.java
deleted file mode 100644
index e15ce6d..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/configuration/ConfigurationValidator.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.configuration;
-
-import com.epam.dlab.core.BillingUtils;
-import com.epam.dlab.exceptions.InitializationException;
-
-import javax.validation.ConstraintViolation;
-import javax.validation.Validation;
-import javax.validation.Validator;
-import javax.validation.ValidatorFactory;
-import java.util.Map;
-import java.util.Set;
-
-/** Json properties validator.
- * @param <T> Class for validation.
- */
-public class ConfigurationValidator<T> {
-	
-	/** Error messages. */
-	private static Map<String, String> messages = BillingUtils.stringsToMap(
-			"{javax.validation.constraints.NotNull.message}", "Property \"%s\" may not be null"); 
-
-	/** Return the list of error messages.
-	 * @param violation constraint violations.
-	 */
-	public String getMessage(ConstraintViolation<T> violation) {
-		return String.format(
-					messages.get(violation.getMessageTemplate()),
-					violation.getPropertyPath(),
-					violation.getInvalidValue());
-	}
-
-	/** Validate properties in instance and throw exception if it have not valid property.
-	 * @param clazz instance for validation.
-	 * @throws InitializationException
-	 */
-	public void validate(T clazz) throws InitializationException {
-		ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
-		Validator validator = validatorFactory.getValidator();
-		Set<ConstraintViolation<T>> violations = validator.validate(clazz);
-		for (ConstraintViolation<T> violation : violations) {
-			throw new InitializationException(getMessage(violation));
-		}
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/configuration/FreeMarkerConfig.java b/services/billing-aws/src/main/java/com/epam/dlab/configuration/FreeMarkerConfig.java
deleted file mode 100644
index 36b7c45..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/configuration/FreeMarkerConfig.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.configuration;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import com.google.common.base.Throwables;
-
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-import freemarker.template.TemplateException;
-
-/** Provides Apache FreeMarker the template engine for the billing configuration.
- */
-public class FreeMarkerConfig {
-	
-	/** Create and return the input stream for the configuration file.
-	 * @param filename the name of configuration file.
-	 * @throws IOException
-	 */
-	public InputStream getInputStream(final String filename) throws IOException {
-		try {
-			Configuration conf = new Configuration(Configuration.VERSION_2_3_22);
-			Template template = new Template("billing-config", new FileReader(new File(filename)), conf);
-			Map<String, Object> dataModel = getDataModel();
-			
-			ByteArrayOutputStream streamBuffer = new ByteArrayOutputStream();
-			template.process(dataModel, new OutputStreamWriter(streamBuffer, StandardCharsets.UTF_8));
-			byte[] buffer = streamBuffer.toByteArray();
-			
-			return new ByteArrayInputStream(buffer);
-		} catch (TemplateException e) {
-			throw Throwables.propagate(e);
-		}
-	}
-
-	/** Create and return JVM and OS properties.
-	 */
-	private Map<String, Object> getDataModel() {
-		Map<String, Object> dataModel = new HashMap<>();
-		
-		Iterator<Object> sysProps = System.getProperties().keySet().iterator();
-		while (sysProps.hasNext()) {
-			String key = (String) sysProps.next();
-			dataModel.put(key, System.getProperties().getProperty(key));
-		}
-		dataModel.putAll(System.getenv());
-
-		dataModel.put("env", System.getenv());
-		dataModel.put("sys", System.getProperties());
-
-		return dataModel;
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/configuration/LoggingConfigurationFactory.java b/services/billing-aws/src/main/java/com/epam/dlab/configuration/LoggingConfigurationFactory.java
deleted file mode 100644
index d96ed51..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/configuration/LoggingConfigurationFactory.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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.configuration;
-
-import ch.qos.logback.classic.Level;
-import ch.qos.logback.classic.Logger;
-import ch.qos.logback.classic.LoggerContext;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.logging.AppenderBase;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import org.slf4j.LoggerFactory;
-
-import javax.validation.Valid;
-
-/** Configuration and factory for logging.
- */
-public class LoggingConfigurationFactory {
-	
-	/** Default logging level for all appenders. */
-	@Valid
-	@JsonProperty
-	private Level level = Level.INFO;
-
-	/** List of logging levels for appenders. */
-	@JsonIgnore
-	private ImmutableMap<String, Level> loggers = ImmutableMap.of();
-
-	/** List of logging appenders. */
-	@Valid
-	@JsonProperty
-	private ImmutableList<AppenderBase> appenders = ImmutableList.of();
-
-
-	/** Return the default logging level for all appenders. */
-	public Level getLevel() {
-		return level;
-	}
-
-	/** Set the default logging level for all appenders. */
-	public void setLevel(String level) throws InitializationException {
-		this.level = toLevel(level);
-	}
-
-	/** Return the list of logging levels for appenders. */
-	public ImmutableMap<String, Level> getLoggers() {
-		return loggers;
-	}
-
-	/** Set the list of logging levels for appenders. */
-	@JsonProperty
-	public void setLoggers(ImmutableMap<String, JsonNode> loggers) throws InitializationException {
-		ImmutableMap.Builder<String, Level> levels = new ImmutableMap.Builder<>();
-		for (String key : loggers.keySet()) {
-			JsonNode node = loggers.get(key);
-			levels.put(key, toLevel(node.asText()));
-		}
-		this.loggers = levels.build();
-	}
-
-	/** Return the list of logging appenders. */
-	public ImmutableList<AppenderBase> getAppenders() {
-		return appenders;
-	}
-
-	/** Set the list of logging appenders. */
-	public void setAppenders(ImmutableList<AppenderBase> appenders) {
-		this.appenders = appenders;
-	}
-	
-	
-	/** Translate the name of logging level to {@link Level}.
-	 * @param level the name of logging level.
-	 * @return logging level.
-	 * @throws InitializationException if given unknown logging level name.
-	 */
-	private Level toLevel(String level) throws InitializationException {
-		Level l = Level.toLevel(level, null);
-		if (l == null) {
-			throw new InitializationException("Unknown logging level: " + level);
-		}
-		return l;
-	}
-
-	/** Configure logging appenders.
-	 * @throws InitializationException
-	 */
-	public void configure() throws InitializationException {
-		if (appenders == null) {
-			throw new InitializationException("Configuration property logging.appenders cannot be null.");
-		}
-		LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
-		context.reset();
-	
-		for (AppenderBase appender : appenders) {
-			appender.configure(context);
-		}
-
-		Logger logger = context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
-		logger.setLevel(level);
-		for (String name : loggers.keySet()) {
-			logger = context.getLogger(name);
-            logger.setLevel(loggers.get(name));
-		}
-	}
-	
-	
-	/** Returns a string representation of the object.
-	 * @param self the object to generate the string for (typically this), used only for its class name.
-	 */
-	public ToStringHelper toStringHelper(Object self) {
-    	return MoreObjects.toStringHelper(self)
-    			.add("level", level)
-    			.add("loggers", loggers)
-    			.add("appenders", appenders);
-    }
-    
-    @Override
-    public String toString() {
-    	return toStringHelper(this)
-    			.toString();
-    }
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/controller/BillingController.java b/services/billing-aws/src/main/java/com/epam/dlab/controller/BillingController.java
deleted file mode 100644
index deabf44..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/controller/BillingController.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.controller;
-
-import com.epam.dlab.BillingService;
-import com.epam.dlab.dto.billing.BillingData;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.List;
-
-@RestController
-public class BillingController {
-
-    private final BillingService billingService;
-
-    public BillingController(BillingService billingService) {
-        this.billingService = billingService;
-    }
-
-    @GetMapping
-    public ResponseEntity<List<BillingData>> getBilling() {
-        return new ResponseEntity<>(billingService.getBillingData(), HttpStatus.OK);
-    }
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/AdapterBase.java b/services/billing-aws/src/main/java/com/epam/dlab/core/AdapterBase.java
deleted file mode 100644
index 475404d..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/AdapterBase.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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.core;
-
-import com.epam.dlab.exceptions.AdapterException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import org.bson.Document;
-
-import java.util.List;
-
-/**
- * Abstract module for read/write adapter.
- * See description of {@link ModuleBase} how to create your own adapter.
- */
-public abstract class AdapterBase extends ModuleBase {
-	public enum Mode {READ, WRITE}
-
-	;
-
-	/**
-	 * Flag the header of common format should be written to target.
-	 */
-	@JsonProperty
-	private boolean writeHeader = true;
-
-
-	/**
-	 * The mode of adapter read or write.
-	 */
-	@JsonIgnore
-	private Mode mode;
-
-
-	/**
-	 * Default constructor for deserialization.
-	 */
-	public AdapterBase() {
-	}
-
-	/**
-	 * Instantiate adapter for reading or writing.
-	 *
-	 * @param mode the mode of adapter.
-	 */
-	public AdapterBase(Mode mode) {
-		this.mode = mode;
-	}
-
-
-	/**
-	 * Return <b>true</b> if the header of common format should be written to target.
-	 */
-	public boolean isWriteHeader() {
-		return writeHeader;
-	}
-
-	/**
-	 * Set flag the header of common format should be written to target.
-	 */
-	public void setWriteHeader(boolean writeHeader) {
-		this.writeHeader = writeHeader;
-	}
-
-
-	/**
-	 * Return the mode of adapter read or write.
-	 */
-	public Mode getMode() {
-		return mode;
-	}
-
-	/**
-	 * Set the mode of adapter read or write.
-	 */
-	public void setMode(Mode mode) {
-		this.mode = mode;
-	}
-
-
-	/**
-	 * Open connection.
-	 *
-	 * @throws AdapterException if cannot open connection.
-	 */
-	public abstract void open() throws AdapterException;
-
-	/**
-	 * Return <b>true</b> if adapter has the multiply entries of data.
-	 */
-	public boolean hasMultyEntry() {
-		return false;
-	}
-
-	/**
-	 * Return <b>true</b> if current entry has the data.
-	 */
-	public boolean hasEntryData() {
-		return true;
-	}
-
-	/**
-	 * Open next entry if exists and return <b>true</b> otherwise return <b>false</b>.
-	 *
-	 * @throws AdapterException if cannot open entry.
-	 */
-	public boolean openNextEntry() throws AdapterException {
-		return false;
-	}
-
-	/**
-	 * Close connection.
-	 *
-	 * @throws AdapterException if cannot close connection.
-	 */
-	public abstract void close() throws AdapterException;
-
-	/**
-	 * Return the current processed entry name.
-	 */
-	public abstract String getEntryName();
-
-	/**
-	 * Read the line of data from adapter and return it.
-	 *
-	 * @throws AdapterException
-	 */
-	public abstract String readLine() throws AdapterException;
-
-	/**
-	 * Write the header of data to adapter.
-	 *
-	 * @param header the header of common format.
-	 * @throws AdapterException
-	 */
-	public abstract void writeHeader(List<String> header) throws AdapterException;
-
-	/**
-	 * Write the row of data to adapter.
-	 *
-	 * @param row the row of common format.
-	 * @return
-	 * @throws AdapterException
-	 */
-	public abstract Document writeRow(ReportLine row) throws AdapterException;
-
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("mode", mode)
-				.add("writeHeader", isWriteHeader());
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/BillingUtils.java b/services/billing-aws/src/main/java/com/epam/dlab/core/BillingUtils.java
deleted file mode 100644
index 50eb871..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/BillingUtils.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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.core;
-
-import java.io.IOException;
-import java.net.URL;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.epam.dlab.configuration.BillingToolConfigurationFactory;
-import com.epam.dlab.core.parser.ParserBase;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.logging.AppenderBase;
-import com.google.common.io.Resources;
-
-/** Billing toll utilities. 
- */
-public class BillingUtils {
-
-	/** Name of resource with the names of module classes. */
-	private static final String RESOURCE_MODULE_NAMES = "/" + BillingToolConfigurationFactory.class.getName();
-
-	private BillingUtils() {
-	}
-	
-	/** Create and return map from given key/values.
-	 * @param keyValues the key/value pairs.
-	 */
-	public static Map<String, String> stringsToMap(String ... keyValues) {
-		Map<String, String> map = new HashMap<>();
-		if (keyValues == null) {
-			return map;
-		}
-		if (keyValues.length % 2 != 0) {
-			throw new IllegalArgumentException("Missing key or value in arguments");
-		}
-		
-		for (int i = 1; i < keyValues.length; i+=2) {
-			map.put(keyValues[i - 1], keyValues[i]);
-		}
-		return map;
-	}
-	
-	/** Read and return content as string list from resource.
-	 * @param resourceName the name of resource.
-	 * @return list of strings.
-	 * @throws InitializationException
-	 */
-	public static List<String> getResourceAsList(String resourceName) throws InitializationException {
-        try {
-    		URL url = BillingToolConfigurationFactory.class.getResource(resourceName);
-            if (url == null) {
-            	throw new InitializationException("Resource " + resourceName + " not found");
-            }
-    		return Resources.readLines(url, Charset.forName("utf-8"));
-		} catch (IllegalArgumentException | IOException e) {
-			throw new InitializationException("Cannot read resource " + resourceName + ": " + e.getLocalizedMessage(), e);
-		}
-	}
-	
-	/** Return the list of billing tool modules.
-	 * @throws InitializationException
-	 */
-	public static List<Class<?>> getModuleClassList() throws InitializationException {
-		List<String> modules = getResourceAsList(RESOURCE_MODULE_NAMES);
-		List<Class<?>> classes = new ArrayList<>();
-		
-		for (String className : modules) {
-			try {
-				classes.add(Class.forName(className));
-			} catch (ClassNotFoundException e) {
-				throw new InitializationException("Cannot add the sub type " + className +
-						" from resource " + RESOURCE_MODULE_NAMES + ": " + e.getLocalizedMessage(), e);
-			}
-		}
-    	return classes;
-	}
-	
-	/** Check for child class is belong to parent by hierarchy.
-	 * @param child the child class for check.
-	 * @param parent the parent class from hierarchy.
-	 */
-	public static boolean classChildOf(Class<?> child, Class<?> parent) {
-		return child != null && parent != null && parent.isAssignableFrom(child);
-	}
-
-	/** Return the type of module if class is module otherwise <b>null</b>.
-	 * @param moduleClass the class.
-	 */
-	public static ModuleType getModuleType(Class<?> moduleClass) {
-		if (classChildOf(moduleClass, AdapterBase.class)) {
-			return ModuleType.ADAPTER;
-		} else if (classChildOf(moduleClass, FilterBase.class)) {
-			return ModuleType.FILTER;
-		} else if (classChildOf(moduleClass, ParserBase.class)) {
-			return ModuleType.PARSER;
-		} else if (classChildOf(moduleClass, AppenderBase.class)) {
-			return ModuleType.LOGAPPENDER;
-		}
-		return null;
-	}
-	
-	/** Return the name of user without domain.
-	 * @param value the value.
-	 */
-	public static String getSimpleUserName(String username) {
-        return (username == null ? null : username.replaceAll("@.*", ""));
-    }
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/DBAdapterBase.java b/services/billing-aws/src/main/java/com/epam/dlab/core/DBAdapterBase.java
deleted file mode 100644
index 65aa2a0..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/DBAdapterBase.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.core;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-/** The abstract adapter for database.
- * See description of {@link ModuleBase} how to create your own adapter.
- */
-public abstract class DBAdapterBase extends AdapterBase {
-
-	/** The host name. */
-    @JsonProperty
-    private String host;
-
-	/** The port. */
-    @JsonProperty
-    private int port;
-
-	/** The name of database. */
-    @JsonProperty
-    private String database;
-
-	/** The name of user. */
-    @JsonProperty
-    private String username;
-
-	/** The password. */
-    @JsonProperty
-    private String password;
-
-    
-	/** Default constructor for deserialization. */
-	public DBAdapterBase() { }
-	
-	/** Instantiate adapter for reading or writing.
-	 * @param mode the mode of adapter.
-	 */
-	public DBAdapterBase(Mode mode) {
-		super(mode);
-	}
-
-	
-	@Override
-	public boolean isWriteHeader() {
-		return false;
-	}
-    
-	/** Return the host name. */
-	public String getHost() {
-		return host;
-	}
-	
-	/** Set the host name. */
-	public void setHost(String host) {
-		this.host = host;
-	}
-	
-	/** Return the port. */
-	public int getPort() {
-		return port;
-	}
-	
-	/** Set the port. */
-	public void setPort(int port) {
-		this.port = port;
-	}
-	
-	/** Return the name of database. */
-	public String getDatabase() {
-		return database;
-	}
-	
-	/** Set the name of database. */
-	public void setDatabase(String database) {
-		this.database = database;
-	}
-	
-	/** Return the name of user. */
-	public String getUsername() {
-		return username;
-	}
-	
-	/** Set the name of user. */
-	public void setUsername(String username) {
-		this.username = username;
-	}
-	
-	/** Return the password. */
-	public String getPassword() {
-		return password;
-	}
-	
-	/** Set the password. */
-	public void setPassword(String password) {
-		this.password = password;
-	}
-	
-	
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("host", host)
-				.add("port", port)
-				.add("database", database)
-				.add("username", username)
-				.add("password", "***");
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/FilterBase.java b/services/billing-aws/src/main/java/com/epam/dlab/core/FilterBase.java
deleted file mode 100644
index 5b51cc5..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/FilterBase.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.core;
-
-import com.epam.dlab.core.parser.ParserBase;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.exceptions.ParseException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import java.util.List;
-
-/**
- * Abstract module of filtering.
- * See description of {@link ModuleBase} how to create your own filter.
- */
-public abstract class FilterBase extends ModuleBase {
-
-	/**
-	 * Parser.
-	 */
-	private ParserBase parser;
-
-	/**
-	 * Return parser.
-	 */
-	public ParserBase getParser() {
-		return parser;
-	}
-
-	/**
-	 * Set parser.
-	 */
-	public void setParser(ParserBase parser) {
-		this.parser = parser;
-	}
-
-
-	/**
-	 * Initialize the filter.
-	 *
-	 * @throws InitializationException
-	 */
-	public abstract void initialize() throws InitializationException;
-
-	/**
-	 * Return the line for parsing if line is accepted and may be parsed,
-	 * otherwise return <b>null</b>.
-	 *
-	 * @param line the source line.
-	 * @throws ParseException
-	 */
-	public abstract String canParse(String line) throws ParseException;
-
-	/**
-	 * Return the list of values for transformation if value is accepted and may be transformed,
-	 * otherwise return <b>null</b>.
-	 *
-	 * @param row the list of values.
-	 * @throws ParseException
-	 */
-	public abstract List<String> canTransform(List<String> row) throws ParseException;
-
-	/**
-	 * Return the row of billing report if row is accepted and may be written to target,
-	 * otherwise return <b>null</b>.
-	 *
-	 * @param row the report line.
-	 * @throws ParseException
-	 */
-	public abstract ReportLine canAccept(ReportLine row) throws ParseException;
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("parser", (parser == null ? null : parser.getType()));
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/ModuleBase.java b/services/billing-aws/src/main/java/com/epam/dlab/core/ModuleBase.java
deleted file mode 100644
index 13e0204..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/ModuleBase.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.core;
-
-import com.epam.dlab.core.parser.ParserBase;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-/** Abstract class for modules: adapter, filter, parser.<br>
- * To create your adapter:<br>
- * 1. Create a class which extends one of {@link AdapterBase}, {@link FilterBase} or {@link ParserBase} classes.<br>
- * 2. Annotate it with {@link JsonTypeName} annotation and give it a unique type name for this type of modules.<br>
- * 3. Add full the name of your class to main/resources/com.epam.dlab.configuration.BillingToolConfigurationFactory file.
- * 4. Annotate it with {@link JsonClassDescription] annotation and describe all properties of module.
- */
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
-public abstract class ModuleBase {
-	
-	/** Working data of module. */
-	@JsonIgnore
-	private ModuleData moduleData;
-	
-	/** Return the name of type for appender. */
-	@JsonIgnore
-	public String getType() {
-		Class<? extends ModuleBase> clazz = this.getClass();
-		return (clazz.isAnnotationPresent(JsonTypeName.class) ?
-				clazz.getAnnotation(JsonTypeName.class).value() : clazz.getName());
-	}
-	
-	/** Return the working data of module. */
-	public ModuleData getModuleData() {
-		return moduleData;
-	}
-	
-	/** Set the working data of module. */
-	public void setModuleData(ModuleData moduleData) {
-		this.moduleData = moduleData;
-	}
-	
-	/** Returns a string representation of the object.
-	 * @param self the object to generate the string for (typically this), used only for its class name.
-	 */
-	public ToStringHelper toStringHelper(Object self) {
-    	return MoreObjects.toStringHelper(self)
-    			.add("type",  getType());
-    }
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/ModuleData.java b/services/billing-aws/src/main/java/com/epam/dlab/core/ModuleData.java
deleted file mode 100644
index 256ab1b..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/ModuleData.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * 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.core;
-
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.mongo.MongoConstants;
-import com.epam.dlab.mongo.MongoDbConnection;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import com.mongodb.client.FindIterable;
-import com.mongodb.client.model.UpdateOptions;
-import org.apache.commons.lang3.StringUtils;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-
-import java.io.IOException;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.gte;
-import static com.mongodb.client.model.Filters.or;
-import static com.mongodb.client.model.Filters.regex;
-
-/**
- * Provides loading and storing the working data of modules.
- */
-public class ModuleData {
-
-	public static final String ENTRIES_FIELD = "entries";
-	private static final String ID_FIELD = "_id";
-	private static final String MODIFICATION_DATE = "lastModificationDate";
-	/**
-	 * Date formatter.
-	 */
-	private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
-	private final MongoDbConnection connection;
-
-	private String id;
-	private Date modificationDate;
-
-	/**
-	 * Entries of data.
-	 */
-	private Map<String, String> entries = new HashMap<>();
-
-	/**
-	 * Flag modification of entries.
-	 */
-	private boolean modified;
-
-	/**
-	 * Instantiate module data.
-	 *
-	 * @param connection the name of data file.
-	 * @throws InitializationException
-	 */
-	public ModuleData(MongoDbConnection connection) {
-		this.connection = connection;
-	}
-
-	/**
-	 * Return <b>true</b> if any entries was modify.
-	 */
-	public boolean isModified() {
-		return modified;
-	}
-
-	public void setId(String id) {
-		this.id = id;
-	}
-
-	public void setModificationDate(Date modificationDate) {
-		this.modificationDate = modificationDate;
-	}
-
-	/**
-	 * Return the value for given key or <b>null</b> if value not found.
-	 *
-	 * @param key the key of entry.
-	 */
-	public String getString(String key) {
-		return entries.get(key);
-	}
-
-	/**
-	 * Return the date value for given key or <b>null</b> if value not found.
-	 *
-	 * @param key the key of entry.
-	 * @throws ParseException
-	 */
-	public Date getDate(String key) throws ParseException {
-		String value = entries.get(key);
-		return (value == null ? null : dateFormat.parse(value));
-	}
-
-	/**
-	 * Set value for given key or delete entry if the value is <b>null</b>.
-	 *
-	 * @param key   the key of entry.
-	 * @param value the value.
-	 */
-	public void set(String key, String value) {
-		if (StringUtils.equals(entries.get(key), value)) {
-			return;
-		} else if (value == null) {
-			entries.remove(key);
-		} else {
-			entries.put(key, value);
-		}
-		modified = true;
-	}
-
-	/**
-	 * Set value for given key or delete entry if the value is <b>null</b>.
-	 *
-	 * @param key   the key of entry.
-	 * @param value the date.
-	 */
-	public void set(String key, Date value) {
-		set(key, dateFormat.format(value));
-	}
-
-	public void store() {
-		final Document document = new Document().append(ID_FIELD, id).append(MODIFICATION_DATE, modificationDate).append(ENTRIES_FIELD, entries);
-		connection.getCollection(MongoConstants.BILLING_DATA_COLLECTION)
-				.updateOne(eq(ID_FIELD, id), new Document("$set", document), new UpdateOptions().upsert(true));
-		modified = false;
-	}
-
-	public boolean wasProcessed(String fileName, Date modificationDate, String datePrefix) {
-		final Bson filePerBillingPeriodCondition = and(regex(ID_FIELD, "^" + datePrefix), gte(MODIFICATION_DATE,
-				modificationDate));
-		final Bson fileWithExactNameCondition = and(eq(ID_FIELD, fileName), gte(MODIFICATION_DATE, modificationDate));
-		final FindIterable<Document> documents = connection.getCollection(MongoConstants.BILLING_DATA_COLLECTION)
-				.find(or(fileWithExactNameCondition, filePerBillingPeriodCondition))
-				.limit(1);
-		return documents.iterator().hasNext();
-	}
-
-	public void closeMongoConnection() throws IOException {
-		connection.close();
-	}
-
-
-	/**
-	 * Returns a string representation of the object.
-	 *
-	 * @param self the object to generate the string for (typically this), used only for its class name.
-	 */
-	public ToStringHelper toStringHelper(Object self) {
-		return MoreObjects.toStringHelper(self)
-				.addValue(entries);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this)
-				.toString();
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/ModuleType.java b/services/billing-aws/src/main/java/com/epam/dlab/core/ModuleType.java
deleted file mode 100644
index fd15ec2..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/ModuleType.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.core;
-
-/** The type of billing modules: adapter, filter, parser or log appender.
- */
-public enum ModuleType {
-	ADAPTER,
-	FILTER,
-	PARSER,
-	LOGAPPENDER;
-	
-    @Override
-    public String toString() {
-        return super.toString().toLowerCase();
-    }
-
-    public static ModuleType of(String string) {
-        if (string != null) {
-            for (ModuleType value : ModuleType.values()) {
-                if (string.equalsIgnoreCase(value.toString())) {
-                    return value;
-                }
-            }
-        }
-        return null;
-    }
-}
\ No newline at end of file
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/aggregate/AggregateGranularity.java b/services/billing-aws/src/main/java/com/epam/dlab/core/aggregate/AggregateGranularity.java
deleted file mode 100644
index b6803e8..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/aggregate/AggregateGranularity.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.core.aggregate;
-
-/** Aggregate granularity for aggregation. */
-public enum AggregateGranularity {
-	NONE,
-    DAY,
-    MONTH;
-
-    @Override
-    public String toString() {
-        return super.toString().toLowerCase();
-    }
-
-    public static AggregateGranularity of(String string) {
-        if (string != null) {
-            for (AggregateGranularity value : AggregateGranularity.values()) {
-                if (string.equalsIgnoreCase(value.toString())) {
-                    return value;
-                }
-            }
-        }
-        return null;
-    }
-}
\ No newline at end of file
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/aggregate/DataAggregator.java b/services/billing-aws/src/main/java/com/epam/dlab/core/aggregate/DataAggregator.java
deleted file mode 100644
index e6f2285..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/aggregate/DataAggregator.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * 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.core.aggregate;
-
-import com.epam.dlab.model.aws.ReportLine;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Vector;
-
-/**
- * Aggregate billing report and summarizes column usage and cost.
- */
-public class DataAggregator {
-	/**
-	 * List of the report lines.
-	 */
-	private final Vector<ReportLine> reportLines = new Vector<>(1000);
-
-	/**
-	 * Comparator for aggregation.
-	 */
-	private final Comparator<ReportLine> aggComparator = new AggComparator();
-
-	/**
-	 * Granularity for aggregation.
-	 */
-	private AggregateGranularity granularity;
-
-	/**
-	 * Length of date for truncate.
-	 */
-	private int truncateDateLength;
-
-
-	public DataAggregator(AggregateGranularity granularity) {
-		switch (granularity) {
-			case DAY:
-				truncateDateLength = 10;
-				break;
-			case MONTH:
-				truncateDateLength = 7;
-				break;
-			default:
-				throw new IllegalArgumentException("Invalid value of granularity argument: expected DAY or MONTH, " +
-						"actual is " + granularity);
-		}
-		this.granularity = granularity;
-	}
-
-	/**
-	 * Return granularity for aggregation.
-	 */
-	public AggregateGranularity getGranularity() {
-		return granularity;
-	}
-
-	/**
-	 * Appends the report line to the list and returns it.
-	 *
-	 * @param row the line of report.
-	 * @return Instance of the aggregated report line.
-	 */
-	public ReportLine append(ReportLine row) {
-		synchronized (this) {
-			String usageInterval = truncDate(row.getUsageDate());
-			row.setUsageDate(usageInterval);
-			int index = Collections.binarySearch(reportLines, row, aggComparator);
-			if (index < 0) {
-				index = -index;
-				if (index > reportLines.size()) {
-					reportLines.add(row);
-				} else {
-					reportLines.add(index - 1, row);
-				}
-			} else {
-				ReportLine found = reportLines.get(index);
-				found.setUsage(found.getUsage() + row.getUsage());
-				found.setCost(found.getCost() + row.getCost());
-				return found;
-			}
-		}
-
-		return row;
-	}
-
-	/**
-	 * Truncate given date for aggregates.
-	 *
-	 * @param date the date.
-	 * @return truncated date.
-	 */
-	private String truncDate(String date) {
-		if (date == null || date.length() <= truncateDateLength) {
-			return date;
-		}
-		return date.substring(0, truncateDateLength);
-	}
-
-	/**
-	 * Returns the number of the report lines in list.
-	 */
-	public int size() {
-		return reportLines.size();
-	}
-
-	/**
-	 * Returns the report line.
-	 *
-	 * @param index index of the report line.
-	 */
-	public ReportLine get(int index) {
-		return reportLines.get(index);
-	}
-
-	/**
-	 * Removes all of the elements from list.
-	 */
-	public void clear() {
-		reportLines.clear();
-	}
-
-	/**
-	 * Comparator for aggregation.
-	 */
-	private class AggComparator implements Comparator<ReportLine> {
-		@Override
-		public int compare(ReportLine o1, ReportLine o2) {
-			if (o1 == null) {
-				return (o2 == null ? 0 : -1);
-			} else if (o2 == null) {
-				return 1;
-			}
-
-			int result = StringUtils.compare(o1.getResourceId(), o2.getResourceId());
-			if (result == 0) {
-				result = StringUtils.compare(o1.getUsageType(), o2.getUsageType());
-				if (result == 0) {
-					result = StringUtils.compare(o1.getUsageDate(), o2.getUsageDate());
-					if (result == 0) {
-						result = StringUtils.compare(o1.getProduct(), o2.getProduct());
-						if (result == 0) {
-							result = StringUtils.compare(o1.getUser(), o2.getUser());
-							if (result == 0) {
-								return StringUtils.compare(o1.getDlabId(), o2.getDlabId());
-							}
-						}
-					}
-				}
-			}
-			return result;
-		}
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/aggregate/UsageDataList.java b/services/billing-aws/src/main/java/com/epam/dlab/core/aggregate/UsageDataList.java
deleted file mode 100644
index 5237290..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/aggregate/UsageDataList.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.core.aggregate;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-/** List of usage dates the billing report data.
- */
-public class UsageDataList implements Iterable<String> {
-	/** List of dates. */
-	private final Map<String, Boolean> map = new HashMap<>();
-	
-	/** Appends the date to the list and returns it.
-	 * @param usageDate the date of data.
-	 * @return Instance of the range.
-	 */
-	public void append(String usageDate) {
-	    synchronized (this) {
-	    	if (!map.containsKey(usageDate)) {
-	    		map.put(usageDate, false);
-	    	}
-	    }
-	}
-
-	/** Returns the number of the range in list. */
-	public int size() {
-		return map.size();
-	}
-
-	/** Returns the value for date.
-	 * @param usageDate the date.
-	 */
-	public Boolean get(String usageDate) {
-		return map.get(usageDate);
-	}
-
-	/** Set the value of usageDate.
-	 * @param usageDate the date.
-	 */
-	public void set(String usageDate, boolean value) {
-		if (map.containsKey(usageDate)) {
-    		map.put(usageDate, value);
-    	}
-	}
-
-	/** Removes all of the elements from list.
-	 */
-	public void clear() {
-		map.clear();
-	}
-
-	@Override
-	public Iterator<String> iterator() {
-		return map.keySet().iterator();
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ColumnInfo.java b/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ColumnInfo.java
deleted file mode 100644
index 058a35e..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ColumnInfo.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.core.parser;
-
-/** Describe the info of column mapping: source to target.
- */
-public class ColumnInfo {
-
-	/** The target column name. */
-	public final String targetName;
-	
-	/** The source column name. */
-	public final String sourceName;
-
-	/** The source column index. */
-	public final int sourceIndex;
-	
-	/** Instantiate the info of column mapping.
-	 * @param targetName the target column name. 
-	 * @param sourceName the source column name.
-	 * @param sourceIndex the source column index.
-	 */
-	public ColumnInfo(String targetName, String sourceName, int sourceIndex) {
-		this.targetName = targetName;
-		this.sourceName = sourceName;
-		this.sourceIndex = sourceIndex;
-	}
-	
-	@Override
-	public String toString() {
-		return targetName + "=" + (sourceName == null ? "" : sourceName + "[" + sourceIndex + "]");
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ColumnMeta.java b/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ColumnMeta.java
deleted file mode 100644
index efeb6bf..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ColumnMeta.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * 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.core.parser;
-
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Provides column meta information.
- */
-public class ColumnMeta {
-	private static final Logger LOGGER = LoggerFactory.getLogger(ColumnMeta.class);
-
-	/**
-	 * Character for separate the tag values and column names.
-	 */
-	public static final char TAG_SEPARATOR = ',';
-	/**
-	 * Character for separate the column mapping.
-	 */
-	public static final char MAPPING_COLUMN_SEPARATOR = ';';
-
-	/**
-	 * The column names for common format.
-	 */
-	static final String[] COLUMN_NAMES = {
-			ReportLine.FIELD_DLAB_ID,
-			ReportLine.FIELD_USER_ID,
-			ReportLine.FIELD_USAGE_DATE,
-			ReportLine.FIELD_PRODUCT,
-			ReportLine.FIELD_USAGE_TYPE,
-			ReportLine.FIELD_USAGE,
-			ReportLine.FIELD_COST,
-			ReportLine.FIELD_CURRENCY_CODE,
-			ReportLine.FIELD_RESOURCE_ID,
-			ReportLine.FIELD_TAGS
-	};
-
-	/**
-	 * The index of the first column for tags.
-	 */
-	public static final int TAG_COLUMN_INDEX = COLUMN_NAMES.length - 1;
-
-	/**
-	 * The list of target column names.
-	 */
-	private List<String> targetColumnNames;
-
-	/**
-	 * The list of source column names.
-	 */
-	private final List<String> sourceColumnNames;
-
-	/**
-	 * The list of column mapping: source to target.
-	 */
-	private List<ColumnInfo> columnMapping;
-
-
-	/**
-	 * Instantiate the common format parser. <b>columnMappingString</b> is semicolon separated
-	 * string with key=value as target=source columns name or indexes of source column. For example,<br>
-	 * "accountId=PayerAccountId;usageIntervalStart=UsageStartDate;usageIntervalEnd=UsageEndDate; ...
-	 * ;tags=user:tag1,user:tag2,user:tagN".
-	 *
-	 * @param columnMappingString column mapping: source to target. if <b>null</b>
-	 *                            the source data will be converted without mapping.
-	 * @param sourceColumnNames   the source column names.
-	 * @throws InitializationException
-	 */
-	public ColumnMeta(String columnMappingString, List<String> sourceColumnNames) throws InitializationException {
-		this.sourceColumnNames = sourceColumnNames;
-		if (columnMappingString != null) {
-			try {
-				setColumnMapping(columnMappingString, sourceColumnNames);
-			} catch (Exception e) {
-				throw new InitializationException("Column mapping error. " + e.getLocalizedMessage(), e);
-			}
-		}
-	}
-
-
-	/**
-	 * Return the list of target column names.
-	 */
-	public List<String> getTargetColumnNames() {
-		return targetColumnNames;
-	}
-
-	/**
-	 * Return the list of source column names.
-	 */
-	public List<String> getSourceColumnNames() {
-		return sourceColumnNames;
-	}
-
-	/**
-	 * Return the list of column mapping: source to target.
-	 */
-	public List<ColumnInfo> getColumnMapping() {
-		return columnMapping;
-	}
-
-
-	/**
-	 * Return the index of column in the list <b>columnNames</b> or throw exception {@link InitializationException}
-	 *
-	 * @param columnName  the name of column.
-	 * @param columnNames the list of column names.
-	 * @return the index of column.
-	 * @throws InitializationException if column not found in the list of columns.
-	 */
-	public static int getColumnIndexByName(String columnName, List<String> columnNames) throws
-			InitializationException {
-		for (int i = 0; i < columnNames.size(); i++) {
-			if (columnName.equals(columnNames.get(i))) {
-				return i;
-			}
-		}
-		throw new InitializationException("Column index not detected for column \"" + columnName + "\"");
-	}
-
-	/**
-	 * Return the index of column in the list <b>columnNames</b> or throw exception {@link InitializationException}.
-	 * columnName may be present as column index. For example like this "$2" for second column.
-	 *
-	 * @param columnName  the name of column or index.
-	 * @param columnNames the list of column names.
-	 * @return the index of column.
-	 * @throws InitializationException if column not found in the list of columns.
-	 */
-	private static int getColumnIndex(String columnName, List<String> columnNames) throws InitializationException {
-		if (columnName.startsWith("$")) {
-			try {
-				return Integer.parseInt(columnName.substring(1)) - 1;
-			} catch (NumberFormatException e) {
-				// Not a column index but column name
-			}
-		}
-		if (columnNames == null) {
-			throw new InitializationException("Invalid column index \"" + columnName + "\"");
-		}
-		return getColumnIndexByName(columnName, columnNames);
-	}
-
-	/**
-	 * Return the index of column in the list <b>columnNames</b> or throw exception {@link InitializationException}.
-	 * columnName may be present as column index. For example like this "$2" for second column.
-	 *
-	 * @param columnName the name of column or index.
-	 * @return the index of column.
-	 * @throws InitializationException if column not found in the list of columns.
-	 */
-	private static int getColumnIndex(String columnName) throws InitializationException {
-		ArrayList<String> list = new ArrayList<>(COLUMN_NAMES.length);
-		for (String s : COLUMN_NAMES) {
-			list.add(s);
-		}
-		return getColumnIndexByName(columnName, list);
-	}
-
-	/**
-	 * Create map of target and source columns for column mapping. Key of map is target column, the value
-	 * is source column. <b>columnMappingString</b> is semicolon separated string with key=value as
-	 * target=source columns name or indexes of source column. For example,<br>
-	 * "accountId=PayerAccountId;usageIntervalStart=UsageStartDate;usageIntervalEnd=UsageEndDate; ...
-	 * ;tags=user:tag1,user:tag2,user:tagN".
-	 *
-	 * @param columnMappingString column mapping: source to target.
-	 * @param sourceColumnNames
-	 * @return Map of target and source columns for column mapping.
-	 * @throws InitializationException
-	 */
-	private Map<String, String> getSourceToTarget(String columnMappingString, List<String> sourceColumnNames) throws
-			InitializationException {
-		String[] entries = StringUtils.split(columnMappingString, MAPPING_COLUMN_SEPARATOR);
-		Map<String, String> sourceToTarget = new HashMap<>();
-
-		for (String entry : entries) {
-			if (entry.trim().isEmpty() || !entry.contains("=")) {
-				throw new InitializationException("Invalid the entry \"" + entry + "\"in column mapping");
-			}
-			String[] pair = StringUtils.split(entry, '=');
-			if (pair.length != 2) {
-				throw new InitializationException("Invalid the entry \"" + entry + "\"in column mapping");
-			}
-
-			pair[0] = pair[0].trim();
-			pair[1] = pair[1].trim();
-
-			try {
-				int index = getColumnIndex(pair[0]);
-				pair[0] = COLUMN_NAMES[index];
-			} catch (InitializationException e) {
-				throw new InitializationException("Unkown target column \"" + pair[0] + "\".", e);
-			}
-
-			try {
-				if (!pair[0].equals(ReportLine.FIELD_TAGS)) {
-					int index = getColumnIndex(pair[1], sourceColumnNames);
-					if (sourceColumnNames != null) {
-						pair[1] = sourceColumnNames.get(index);
-					}
-				}
-			} catch (InitializationException e) {
-				if (sourceColumnNames == null) {
-					throw new InitializationException("Invalid column index \"" + pair[1] + "\" or column header not " +
-							"defined");
-				}
-				throw new InitializationException("Unkown source column \"" + pair[1] + "\".", e);
-			}
-			sourceToTarget.put(pair[0], pair[1]);
-		}
-
-		return sourceToTarget;
-	}
-
-	/**
-	 * Initialize and set column mapping. <b>columnMappingString</b> is semicolon separated string with key=value as
-	 * target=source columns name or indexes of source column. For example,<br>
-	 * "accountId=PayerAccountId;usageIntervalStart=UsageStartDate;usageIntervalEnd=UsageEndDate; ...
-	 * ;tags=user:tag1,user:tag2,user:tagN".
-	 *
-	 * @param columnMappingString column mapping: source to target. if <b>null</b>
-	 *                            the source data will be converted without mapping.
-	 * @param sourceColumnNames   the list of source column names.
-	 * @throws InitializationException
-	 */
-	private void setColumnMapping(String columnMappingString, List<String> sourceColumnNames) throws
-			InitializationException {
-		if (columnMappingString == null) {
-			throw new InitializationException("Mapping not defined.");
-		}
-
-		Map<String, String> sourceToTarget = getSourceToTarget(columnMappingString, sourceColumnNames);
-		String tags = sourceToTarget.get(ReportLine.FIELD_TAGS);
-		List<String> tagColumns = (tags == null ? null :
-				Arrays.asList(StringUtils.split(tags, TAG_SEPARATOR)));
-
-		LOGGER.info("Mapping columns [target=source:name[index]]:");
-		int columnCount = COLUMN_NAMES.length - 1;
-		int tagCount = (tagColumns == null ? 0 : tagColumns.size());
-		columnMapping = new ArrayList<>(columnCount + tagCount);
-		targetColumnNames = new ArrayList<>(columnCount + tagCount);
-
-		for (int i = 0; i < columnCount; i++) {
-			String sourceName = sourceToTarget.get(COLUMN_NAMES[i]);
-			ColumnInfo columnInfo = new ColumnInfo(
-					COLUMN_NAMES[i],
-					sourceName,
-					(sourceName == null ? -1 : getColumnIndex(sourceName, sourceColumnNames)));
-			columnMapping.add(columnInfo);
-			targetColumnNames.add(COLUMN_NAMES[i]);
-			LOGGER.info("  " + columnInfo.toString());
-		}
-
-		for (int i = 0; i < tagCount; i++) {
-			String sourceName = tagColumns.get(i).trim();
-			int sourceIndex = getColumnIndex(sourceName, sourceColumnNames);
-			if (sourceColumnNames != null) {
-				sourceName = sourceColumnNames.get(sourceIndex);
-			}
-			ColumnInfo columnInfo = new ColumnInfo(
-					ReportLine.FIELD_TAGS,
-					sourceName,
-					sourceIndex);
-			columnMapping.add(columnInfo);
-			targetColumnNames.add(sourceName);
-			LOGGER.info("  " + columnInfo.toString());
-		}
-	}
-
-
-	/**
-	 * Returns a string representation of the object.
-	 *
-	 * @param self the object to generate the string for (typically this), used only for its class name.
-	 */
-	public ToStringHelper toStringHelper(Object self) {
-		return MoreObjects.toStringHelper(self)
-				.add("targetColumnNames", targetColumnNames)
-				.add("sourceColumnNames", sourceColumnNames)
-				.add("columnMapping", columnMapping);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/CommonFormat.java b/services/billing-aws/src/main/java/com/epam/dlab/core/parser/CommonFormat.java
deleted file mode 100644
index 2b5b7fa..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/CommonFormat.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * 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.core.parser;
-
-import com.epam.dlab.exceptions.ParseException;
-import com.epam.dlab.model.aws.ReportLine;
-import org.apache.commons.lang3.StringUtils;
-
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-
-/**
- * Provides common format features.
- */
-public class CommonFormat {
-	/**
-	 * Character for separate field names and values.
-	 */
-	public static final char FIELD_SEPARATOR = ',';
-
-	/**
-	 * Character for termination field names and values.
-	 */
-	public static final char FIELD_DELIMITER = '"';
-
-	/**
-	 * Escape character.
-	 */
-	public static final char ESCAPE_CHAR = '\\';
-
-	/**
-	 * Default character used for decimal sign.
-	 */
-	public static final char DECIMAL_SEPARATOR_DEFAULT = '.';
-
-	/**
-	 * Default character used for thousands separator.
-	 */
-	public static final char DECIMAL_GROUPING_SEPARATOR_DEFAULT = ' ';
-
-	/**
-	 * String of the field separator for replacement to target data.
-	 */
-	private static final String DELIMITER_REPLACE_FROM = String.valueOf(FIELD_DELIMITER);
-
-	/**
-	 * String of the escaped field separator for replacement to target data.
-	 */
-	private static final String DELIMITER_REPLACE_TO = new StringBuilder()
-			.append(ESCAPE_CHAR)
-			.append(FIELD_DELIMITER)
-			.toString();
-
-	/**
-	 * Formatter for convert decimal numbers to string.
-	 */
-	private static final DecimalFormat DECIMAL_TO_STRING_FORMAT;
-
-	static {
-		DECIMAL_TO_STRING_FORMAT = new DecimalFormat();
-		DecimalFormatSymbols symbols = new DecimalFormatSymbols();
-		symbols.setDecimalSeparator(DECIMAL_SEPARATOR_DEFAULT);
-		DECIMAL_TO_STRING_FORMAT.setDecimalFormatSymbols(symbols);
-		DECIMAL_TO_STRING_FORMAT.setGroupingUsed(false);
-		DECIMAL_TO_STRING_FORMAT.setMaximumFractionDigits(100);
-	}
-
-
-	/**
-	 * Column meta information.
-	 */
-	private final ColumnMeta columnMeta;
-
-	/**
-	 * Formatter for parse of decimal number .
-	 */
-	private final DecimalFormat sourceDecimalFormat;
-
-
-	/**
-	 * Instantiate the helper for common format.
-	 *
-	 * @param columnMeta column meta information.
-	 */
-	public CommonFormat(ColumnMeta columnMeta) {
-		this(columnMeta, DECIMAL_SEPARATOR_DEFAULT, DECIMAL_GROUPING_SEPARATOR_DEFAULT);
-	}
-
-	/**
-	 * Instantiate the helper for common format.
-	 *
-	 * @param columnMeta        column meta information.
-	 * @param decimalSeparator  the character used for decimal sign.
-	 * @param groupingSeparator the character used for thousands separator.
-	 */
-	public CommonFormat(ColumnMeta columnMeta, char sourceDecimalSeparator, char sourceGroupingSeparator) {
-		this.columnMeta = columnMeta;
-		this.sourceDecimalFormat = getDecimalFormat(sourceDecimalSeparator, sourceGroupingSeparator);
-	}
-
-
-	/**
-	 * Create and return the target row for common format from source.
-	 *
-	 * @param sourceRow the source row.
-	 * @return row in common format.
-	 * @throws ParseException
-	 */
-	public ReportLine toCommonFormat(List<String> sourceRow) throws ParseException {
-		if (columnMeta.getColumnMapping() == null) {
-			return toReportLine(sourceRow);
-		}
-
-		List<String> targetRow = new ArrayList<>();
-		for (ColumnInfo columnInfo : columnMeta.getColumnMapping()) {
-			targetRow.add((columnInfo.sourceIndex < 0 ? "" :
-					(columnInfo.sourceIndex < sourceRow.size() ? sourceRow.get(columnInfo.sourceIndex) : null)));
-		}
-		return toReportLine(targetRow);
-	}
-
-	/**
-	 * Add the column value to string in CSV format.
-	 *
-	 * @param sb    the buffer of sting.
-	 * @param value the value.
-	 * @return the buffer of string.
-	 */
-	private static StringBuilder addToStringBuilder(StringBuilder sb, String value) {
-		if (sb.length() > 0) {
-			sb.append(FIELD_SEPARATOR);
-		}
-		return sb.append(FIELD_DELIMITER)
-				.append(StringUtils.replace(value, DELIMITER_REPLACE_FROM, DELIMITER_REPLACE_TO))
-				.append(FIELD_DELIMITER);
-	}
-
-	/**
-	 * Convert row to line in CSV format.
-	 *
-	 * @param row row for convertation.
-	 * @return string in CSV format.
-	 */
-	public static String rowToString(List<String> row) {
-		StringBuilder sb = new StringBuilder();
-		for (String s : row) {
-			addToStringBuilder(sb, s);
-		}
-		return sb.toString();
-	}
-
-	/**
-	 * Convert row to line in CSV format.
-	 *
-	 * @param row row for convertation.
-	 * @return string in CSV format.
-	 */
-	public static String rowToString(ReportLine row) {
-		StringBuilder sb = new StringBuilder();
-
-		addToStringBuilder(sb, row.getDlabId());
-		addToStringBuilder(sb, row.getUser());
-		addToStringBuilder(sb, row.getUsageDate());
-		addToStringBuilder(sb, row.getProduct());
-		addToStringBuilder(sb, row.getUsageType());
-		addToStringBuilder(sb, doubleToString(row.getUsage()));
-		addToStringBuilder(sb, doubleToString(row.getCost()));
-		addToStringBuilder(sb, row.getCurrencyCode());
-		addToStringBuilder(sb, row.getResourceType().toString());
-		addToStringBuilder(sb, row.getResourceId());
-
-		if (row.getTags() != null) {
-			for (String key : row.getTags().keySet()) {
-				addToStringBuilder(sb, row.getTags().get(key));
-			}
-		}
-		return sb.toString();
-	}
-
-	/**
-	 * Create and return decimal formatter.
-	 *
-	 * @param decimalSeparator  the character used for decimal sign.
-	 * @param groupingSeparator the character used for thousands separator.
-	 * @return Formatter for decimal digits.
-	 */
-	private DecimalFormat getDecimalFormat(char decimalSeparator, char groupingSeparator) {
-		DecimalFormat df = new DecimalFormat();
-		DecimalFormatSymbols symbols = new DecimalFormatSymbols();
-		symbols.setDecimalSeparator(decimalSeparator);
-		symbols.setGroupingSeparator(groupingSeparator);
-		df.setDecimalFormatSymbols(symbols);
-		return df;
-	}
-
-	/**
-	 * Parse and return double value. If value is <b>null</b> or empty return zero.
-	 *
-	 * @param columnName the name of column.
-	 * @param value      the value.
-	 * @throws ParseException
-	 */
-	public double parseDouble(String columnName, String value) throws ParseException {
-		if (value == null || value.trim().isEmpty()) {
-			return 0;
-		}
-		try {
-			return sourceDecimalFormat.parse(value).doubleValue();
-		} catch (Exception e) {
-			throw new ParseException("Cannot cast column " + columnName + " value \"" + value + "\" to double: " + e
-					.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Return the string representation of double value.
-	 *
-	 * @param value the value.
-	 */
-	public static String doubleToString(double value) {
-		return DECIMAL_TO_STRING_FORMAT.format(value);
-	}
-
-	/**
-	 * Creates and returns the line of billing report from the list of values.
-	 *
-	 * @param row the list of values.
-	 * @return the line of billing report.
-	 * @throws ParseException
-	 */
-	public ReportLine toReportLine(List<String> row) throws ParseException {
-		if (row.size() < ColumnMeta.TAG_COLUMN_INDEX || row.size() > columnMeta.getTargetColumnNames().size()) {
-			throw new ParseException("Invalid the number of columns in list: expected from " + ColumnMeta
-					.TAG_COLUMN_INDEX +
-					" to " + columnMeta.getTargetColumnNames().size() + ", actual " + row.size());
-		}
-		ReportLine line = new ReportLine();
-		int i = 0;
-
-		line.setDlabId(row.get(i));
-		line.setUser(row.get(++i));
-		line.setUsageDate(row.get(++i));
-		line.setProduct(row.get(++i));
-		line.setUsageType(row.get(++i));
-		line.setUsage(parseDouble("usage", row.get(++i)));
-		line.setCost(parseDouble("cost", row.get(++i)));
-		line.setCurrencyCode(row.get(++i));
-		line.setResourceTypeId(row.get(++i));
-
-		if (row.size() >= ColumnMeta.TAG_COLUMN_INDEX) {
-			LinkedHashMap<String, String> tags = new LinkedHashMap<>();
-			i++;
-			while (i < row.size()) {
-				tags.put(columnMeta.getTargetColumnNames().get(i), row.get(i++));
-			}
-			line.setTags(tags);
-		}
-
-		return line;
-	}
-
-
-	/**
-	 * Print row to console.
-	 *
-	 * @param row array of values.
-	 */
-	public static void printRow(String[] row) {
-		System.out.print(" | ");
-		for (String s : row) {
-			System.out.print(s + " | ");
-		}
-		System.out.println();
-	}
-
-	/**
-	 * Print row to console.
-	 *
-	 * @param row list of values.
-	 */
-	public static void printRow(List<String> row) {
-		printRow(row.toArray(new String[row.size()]));
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ConditionEvaluate.java b/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ConditionEvaluate.java
deleted file mode 100644
index 708fea8..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ConditionEvaluate.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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.core.parser;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.jexl3.JexlBuilder;
-import org.apache.commons.jexl3.JexlContext;
-import org.apache.commons.jexl3.JexlEngine;
-import org.apache.commons.jexl3.MapContext;
-import org.apache.commons.jexl3.internal.Script;
-import org.apache.commons.lang3.StringUtils;
-
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.exceptions.ParseException;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-/** Evaluate condition for filtering source data.
- */
-public class ConditionEvaluate {
-
-	/** Names of columns for condition. */
-	private String [] columnNames;
-
-	/** Indexes of columns for condition. */
-	private int [] columnIndexes;
-
-	/** JEXL expression for evaluation. */
-	private final Script expression;
-
-	/** JEXL context to evaluate row. */
-	private final JexlContext jexlContext;
-	
-	/** Instantiate the engine to evaluate condition. 
-	 * @param columnNames the list of column names.
-	 * @param condition condition for filtering data.
-	 * @throws InitializationException
-	 */
-	public ConditionEvaluate(List<String> columnNames, String condition) throws InitializationException {
-		//Replace : to . in column names
-		List<String> colNames = new ArrayList<>(columnNames.size());
-		for (int i = 0; i < columnNames.size(); i++) {
-			String name = columnNames.get(i);
-			if (name.indexOf(':') > -1 && condition.indexOf(name) > -1) {
-				String newName = StringUtils.replaceChars(name, ':', '.');
-				colNames.add(newName);
-				condition = StringUtils.replace(condition, name, newName);
-			} else {
-				colNames.add(name);
-			}
-		}
-
-		try {
-			JexlEngine engine = new JexlBuilder().strict(true).silent(false).debug(true).create();
-			expression = (Script) engine.createExpression(condition);
-			jexlContext = new MapContext();
-		} catch (Exception e) {
-			throw new InitializationException("Cannot initialize JEXL engine for condition: " + condition + ". " +
-							e.getLocalizedMessage(), e);
-		}
-		
-		// Create mapping of columns for evaluations. 
-		List<String> names = new ArrayList<>();
-		List<Integer> indexes = new ArrayList<>();
-		for (List<String> variableList : expression.getVariables()) {
-			String columnName = StringUtils.join(variableList, '.');
-			int index = getColumnIndex(colNames, columnName);
-	    	if (index == -1) {
-	    		throw new InitializationException("Unknow source column name \"" + columnName + "\" in condition: " +
-	    				expression.getSourceText() + ". Known column names: " + StringUtils.join(columnNames, ", ") + ".");
-	    	}
-	    	names.add(columnName);
-	    	indexes.add(index);
-		}
-		
-		this.columnNames = new String[names.size()];
-		this.columnIndexes = new int[indexes.size()];
-		for (int i = 0; i < indexes.size(); i++) {
-			this.columnNames[i] = names.get(i);
-			this.columnIndexes[i] = indexes.get(i);
-		}
-	}
-	
-	/** Find and return the index of column in the given column list.
-	 * @param columnNames the list of column names.
-	 * @param columnName the name of column to find.
-	 */
-	private int getColumnIndex(List<String> columnNames, String columnName) {
-		for (int i = 0; i < columnNames.size(); i++) {
-			if (columnName.equals(columnNames.get(i))) {
-				return i;
-			}
-		}
-		return -1;
-	}
-	
-	/** Evaluate condition for given row.
-	 * @param row the row to evaluate.
-	 * @return <true> if condition is true.
-	 * @throws ParseException if condition is not return boolean type.
-	 */
-	public boolean evaluate(List<String> row) throws ParseException {
-		for (int i = 0; i < columnNames.length; i++) {
-			jexlContext.set(columnNames[i], row.get(columnIndexes[i]));
-		}
-	    Object value;
-	    try {
-	    	value = expression.evaluate(jexlContext);
-	    } catch (Exception e) {
-	    	throw new ParseException("Cannot evaluate condition: " + expression.getSourceText() + ". " +
-	    				e.getLocalizedMessage(), e);
-	    }
-		if (value instanceof Boolean) {
-			return (Boolean)value;
-		}
-	    throw new ParseException("Invalid condition: " + expression.getSourceText());
-	}
-
-	
-	/** Returns a string representation of the object.
-	 * @param self the object to generate the string for (typically this), used only for its class name.
-	 */
-	public ToStringHelper toStringHelper(Object self) {
-    	return MoreObjects.toStringHelper(self)
-    			.add("columnNames",  columnNames)
-    			.add("columnIndexes", columnIndexes);
-    }
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ParserBase.java b/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ParserBase.java
deleted file mode 100644
index bfd86bc..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ParserBase.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * 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.core.parser;
-
-import com.epam.dlab.core.AdapterBase;
-import com.epam.dlab.core.FilterBase;
-import com.epam.dlab.core.ModuleBase;
-import com.epam.dlab.core.aggregate.AggregateGranularity;
-import com.epam.dlab.core.aggregate.DataAggregator;
-import com.epam.dlab.exceptions.AdapterException;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.exceptions.ParseException;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import org.apache.commons.lang3.StringUtils;
-import org.bson.Document;
-
-import javax.validation.constraints.NotNull;
-import java.util.ArrayList;
-import java.util.List;
-
-/** Abstract module of parser.<br>
- * See description of {@link ModuleBase} how to create your own parser.
- */
-public abstract class ParserBase extends ModuleBase {
-	
-	/** Default character used for decimal sign. */
-	public static final char DECIMAL_SEPARATOR_DEFAULT = '.';
-	
-	/** Default character used for thousands separator. */
-	public static final char DECIMAL_GROUPING_SEPARATOR_DEFAULT = ' ';
-	
-	/** Name of key for date report data. */
-	public static final String DATA_KEY_START_DATE = "ParserBase.maxStartDate";
-
-	
-	/** Mapping columns from source format to target. */
-	@JsonProperty
-	private String columnMapping = null;
-	
-	/** Where condition for filtering the source data. */
-	@JsonProperty
-	private String whereCondition = null;
-	
-	/** How to aggregate the parsed data. */
-	@JsonProperty
-	@NotNull
-	private AggregateGranularity aggregate = AggregateGranularity.NONE;
-	
-	/** Character used for decimal sign of source data. */
-	@JsonProperty
-	@NotNull
-	private char decimalSeparator = DECIMAL_SEPARATOR_DEFAULT;
-	
-	/** Character used for thousands separator of source data. */
-	@JsonProperty
-	@NotNull
-	private char groupingSeparator = DECIMAL_GROUPING_SEPARATOR_DEFAULT;
-
-
-	/** Adapter for reading source data. */
-	@JsonIgnore
-	private AdapterBase adapterIn;
-	
-	/** Adapter for writing converted data. */
-	@JsonIgnore
-	private AdapterBase adapterOut;
-	
-	/** Filter for source and converted data. */
-	@JsonIgnore
-	private FilterBase filter;
-
-
-	/** Column meta information. */
-	@JsonIgnore
-	private ColumnMeta columnMeta;
-	
-	/** Condition for filtering the source data. */
-	@JsonIgnore
-	private ConditionEvaluate condition;
-	
-	/** Aggregator of billing report.*/
-	@JsonIgnore
-	private DataAggregator aggregator;
-	
-	/** Common format helper. */
-	@JsonIgnore
-	private CommonFormat commonFormat;
-
-	/** Parser statistics. */
-	@JsonIgnore
-	private final List<ParserStatistics> statistics = new ArrayList<>();
-	
-	/** Current parser statistics. */
-	@JsonIgnore
-	ParserStatistics currentStatistics = null; 
-	
-	
-	/** Return mapping columns from source format to target. */
-	public String getColumnMapping() {
-		return columnMapping;
-	}
-
-	/** Set mapping columns from source format to target. */
-	public void setColumnMapping(String columnMapping) {
-		this.columnMapping = columnMapping;
-	}
-
-	/** Return where condition for filtering the source data. */
-	public String getWhereCondition() {
-		return whereCondition;
-	}
-
-	/** Set where condition for filtering the source data. */
-	public void setWhereCondition(String whereCondition) {
-		this.whereCondition = whereCondition;
-	}
-
-	/** Return how to aggregate the parsed data. */
-	public AggregateGranularity getAggregate() {
-		return aggregate;
-	}
-
-	/** Set how to aggregate the parsed data.
-	 * @throws InitializationException */
-	public void setAggregate(String aggregate) throws InitializationException {
-		if (aggregate == null) {
-			throw new InitializationException("Property aggregate cannot be null");
-		}
-		AggregateGranularity value = AggregateGranularity.of(aggregate);
-        if (value == null) {
-        	throw new InitializationException("Invalid value \"" + aggregate + "\" for property aggregate. " +
-					"Should be one of: " + StringUtils.join(AggregateGranularity.values(), ", "));
-        }
-		this.aggregate = value;
-	}
-
-	/** Return character used for decimal sign of source data. */
-	public char getDecimalSeparator() {
-		return decimalSeparator;
-	}
-	
-	/** Set character used for decimal sign of source data. */
-	public void setDecimalSeparator(char decimalSeparator) {
-		this.decimalSeparator = decimalSeparator;
-	}
-	
-	/** Return character used for thousands separator of source data. */
-	public char getGroupingSeparator() {
-		return groupingSeparator;
-	}
-	
-	/** Set character used for thousands separator of source data. */
-	public void setGroupingSeparator(char groupingSeparator) {
-		this.groupingSeparator = groupingSeparator;
-	}
-	
-	
-	/** Return the adapter for reading source data. */
-	public AdapterBase getAdapterIn() {
-		return adapterIn;
-	}
-
-	/** Return the adapter for writing converted data. */
-	public AdapterBase getAdapterOut() {
-		return adapterOut;
-	}
-	
-	/** Return the filter for source and converted data. */
-	public FilterBase getFilter() {
-		return filter;
-	}
-
-	/** Return the column meta information. */
-	public ColumnMeta getColumnMeta() {
-		return columnMeta;
-	}
-	
-	/** Return the condition for filtering the source data. */
-	public ConditionEvaluate getCondition() {
-		return condition;
-	}
-	
-	/** Return the aggregator of billing report.*/
-	public DataAggregator getAggregator() {
-		return aggregator;
-	}
-	
-	/** Return the common format helper. */
-	public CommonFormat getCommonFormat() {
-		return commonFormat;
-	}
-	
-	/** Return the parser statistics. */
-	public List<ParserStatistics> getStatistics() {
-		return statistics;
-	}
-	
-	/** Add and return the new instance for statistics.
-	 * @param entryName the name of new entry.
-	 */
-	public ParserStatistics addStatistics(String entryName) {
-		currentStatistics = new ParserStatistics(entryName);
-		statistics.add(currentStatistics);
-		return currentStatistics;
-	}
-	
-	/** Return the current parser statistics. */
-	public ParserStatistics getCurrentStatistics() {
-		return currentStatistics;
-	}
-
-	
-	/** Initialize the parser.
-	 * @throws InitializationException
-	 */
-	public abstract void initialize()  throws InitializationException;
-
-	/**
-	 * Parse the source data to common format and write it to output adapter.
-	 *
-	 * @return
-	 * @throws InitializationException
-	 * @throws AdapterException
-	 * @throws ParseException
-	 */
-	public abstract List<Document> parse() throws InitializationException, AdapterException, ParseException;
-	
-	/** Build parser from given modules.
-	 * @param adapterIn the adapter for reading source data.
-	 * @param adapterOut the adapter for writing converted data.
-	 * @param filter the filter for source and converted data. May be <b>null<b>.
-	 */
-	public ParserBase build(AdapterBase adapterIn, AdapterBase adapterOut, FilterBase filter) {
-		this.adapterIn = adapterIn;
-		this.adapterOut = adapterOut;
-		if (filter != null) {
-			filter.setParser(this);
-		}
-		this.filter = filter;
-		return this;
-	}
-	
-	
-	/** Initialize ParserBase.
-	 * @param header - the header of source data.
-	 * @throws InitializationException
-	 * @throws AdapterException
-	 */
-	protected void init(List<String> header) throws InitializationException, AdapterException {
-		columnMeta = new ColumnMeta(columnMapping, header);
-		if (whereCondition != null) {
-			if (columnMeta.getSourceColumnNames() == null) {
-				throw new InitializationException("To use the whereCondition property you must specify and have the header of source data");
-			}
-			condition = new ConditionEvaluate(columnMeta.getSourceColumnNames(), whereCondition);
-		} else {
-			condition = null;
-		}
-		commonFormat = new CommonFormat(columnMeta, decimalSeparator, groupingSeparator);
-
-		if (aggregate != AggregateGranularity.NONE) {
-			aggregator = new DataAggregator(aggregate);
-		}
-
-		if (getAdapterOut().isWriteHeader()) {
-			getAdapterOut().writeHeader(columnMeta.getTargetColumnNames());
-		}
-	}
-	
-	
-	/** Return the index of source column by column name. 
-	 * @param columnName the name of column.
-	 * @throws InitializationException
-	 */
-	public int getSourceColumnIndexByName(String columnName) throws InitializationException {
-		return ColumnMeta.getColumnIndexByName(columnName, columnMeta.getSourceColumnNames());
-	}
-	
-	
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-    	return super.toStringHelper(self)
-    			.add("adapterIn", (adapterIn == null ? null : adapterIn.getType()))
-    			.add("adapterOut", (adapterOut == null ? null : adapterOut.getType()))
-    			.add("filter", (filter == null ? null : filter.getType()))
-    			.add("columnMapping", columnMapping)
-    			.add("whereCondition", whereCondition)
-    			.add("aggregate", aggregate)
-    			.add("decimalSeparator", decimalSeparator)
-    			.add("groupingSeparator", groupingSeparator);
-    }
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ParserByLine.java b/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ParserByLine.java
deleted file mode 100644
index 0fbdc5f..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ParserByLine.java
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * 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.core.parser;
-
-import com.epam.dlab.core.ModuleBase;
-import com.epam.dlab.core.aggregate.AggregateGranularity;
-import com.epam.dlab.exceptions.AdapterException;
-import com.epam.dlab.exceptions.GenericException;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.exceptions.ParseException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import org.bson.Document;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Abstract module of parser by the line.<br>
- * See description of {@link ModuleBase} how to create your own parser.
- */
-public abstract class ParserByLine extends ParserBase {
-	private static final Logger LOGGER = LoggerFactory.getLogger(ParserByLine.class);
-	private static final String ENTRY_NAME = "\nEntry name: ";
-	private static final String SOURCE_LINE = "\nSource line[";
-
-	/**
-	 * Parse the header of source data and return it.
-	 *
-	 * @return the header of source data.
-	 * @throws AdapterException
-	 * @throws ParseException
-	 */
-	public abstract List<String> parseHeader() throws AdapterException, ParseException;
-
-	/**
-	 * Parse the row from source line and return result row.
-	 *
-	 * @param line the source line.
-	 * @return the parsed row.
-	 * @throws ParseException
-	 */
-	public abstract List<String> parseRow(String line) throws ParseException;
-
-	/**
-	 * Read the line from adapter and return it.
-	 *
-	 * @return the parsed row from adapterIn.
-	 * @throws AdapterException
-	 */
-	@JsonIgnore
-	public String getNextRow() throws AdapterException {
-		String line = getAdapterIn().readLine();
-		if (line == null) {
-			return null;
-		}
-		getCurrentStatistics().incrRowReaded();
-		return line;
-	}
-
-	/**
-	 * Initialize ParserBase.
-	 *
-	 * @throws InitializationException
-	 * @throws AdapterException
-	 * @throws ParseException
-	 */
-	protected boolean init() throws InitializationException, AdapterException, ParseException {
-		getAdapterIn().open();
-		LOGGER.debug("Source data has multy entry {}", getAdapterIn().hasMultyEntry());
-		if (!initEntry()) {
-			return false;
-		}
-		getAdapterOut().open();
-		return true;
-	}
-
-	/**
-	 * Initialize for each entry ParserBase.
-	 *
-	 * @throws InitializationException
-	 * @throws AdapterException
-	 * @throws ParseException
-	 */
-	private boolean initEntry() throws InitializationException, AdapterException, ParseException {
-		if (getAdapterIn().hasMultyEntry() && !getAdapterIn().hasEntryData()) {
-			return false;
-		}
-		addStatistics(getAdapterIn().getEntryName());
-		getCurrentStatistics().start();
-
-		super.init(parseHeader());
-		initialize();
-		if (getFilter() != null) {
-			getFilter().initialize();
-		}
-		return true;
-	}
-
-	/**
-	 * Close adapters.
-	 *
-	 * @throws AdapterException
-	 */
-	protected void close(boolean silent) throws AdapterException {
-		AdapterException ex = null;
-		try {
-			getAdapterIn().close();
-		} catch (Exception e) {
-			if (silent) {
-				LOGGER.warn("Cannot close adapterIn. {}", e.getLocalizedMessage(), e);
-			} else {
-				ex = new AdapterException("Cannot close adapterIn. " + e.getLocalizedMessage(), e);
-			}
-		}
-		try {
-			getAdapterOut().close();
-		} catch (Exception e) {
-			if (silent || ex != null) {
-				LOGGER.warn("Cannot close adapterOut. {}", e.getLocalizedMessage(), e);
-			} else {
-				ex = new AdapterException("Cannot close adapterOut. " + e.getLocalizedMessage(), e);
-			}
-		}
-		try {
-			getModuleData().closeMongoConnection();
-		} catch (IOException e) {
-			if (silent || ex != null) {
-				LOGGER.warn("Cannot close mongo connection. {}", e.getLocalizedMessage(), e);
-			} else {
-				ex = new AdapterException("Cannot close mongo connection. " + e.getLocalizedMessage(), e);
-			}
-		}
-		if (!silent && ex != null) {
-			throw ex;
-		}
-	}
-
-	/**
-	 * Parse the source data to common format and write it to output adapter.
-	 *
-	 * @return list of billing data
-	 * @throws InitializationException
-	 * @throws AdapterException
-	 * @throws ParseException
-	 */
-	public List<Document> parse() throws InitializationException, AdapterException, ParseException {
-		List<Document> billingData = new ArrayList<>();
-		try {
-			if (init()) {
-				String line;
-				List<String> row;
-				ReportLine reportLine;
-				LOGGER.info("Parsing {}", getAdapterIn().getEntryName());
-
-				while ((line = getNextRow()) != null) {
-					if (getFilter() != null && (line = getFilter().canParse(line)) == null) {
-						getCurrentStatistics().incrRowFiltered();
-						continue;
-					}
-
-					row = parseRow(line);
-					if ((getFilter() != null && (row = getFilter().canTransform(row)) == null)) {
-						getCurrentStatistics().incrRowFiltered();
-						continue;
-					}
-					try {
-						if (getCondition() != null && !getCondition().evaluate(row)) {
-							getCurrentStatistics().incrRowFiltered();
-							continue;
-						}
-					} catch (ParseException e) {
-						throw new ParseException(e.getLocalizedMessage() + ENTRY_NAME + getCurrentStatistics().getEntryName() +
-								SOURCE_LINE + getCurrentStatistics().getRowReaded() + "]: " + line, e);
-					} catch (Exception e) {
-						throw new ParseException("Cannot evaluate condition " + getWhereCondition() + ". " +
-								e.getLocalizedMessage() + ENTRY_NAME + getCurrentStatistics().getEntryName() +
-								SOURCE_LINE + getCurrentStatistics().getRowReaded() + "]: " + line, e);
-					}
-
-					try {
-						reportLine = getCommonFormat().toCommonFormat(row);
-					} catch (ParseException e) {
-						throw new ParseException("Cannot cast row to common format. " +
-								e.getLocalizedMessage() + ENTRY_NAME + getCurrentStatistics().getEntryName() +
-								SOURCE_LINE + getCurrentStatistics().getRowReaded() + "]: " + line, e);
-					}
-					if (getFilter() != null && (reportLine = getFilter().canAccept(reportLine)) == null) {
-						getCurrentStatistics().incrRowFiltered();
-						continue;
-					}
-
-					getCurrentStatistics().incrRowParsed();
-					if (getAggregate() != AggregateGranularity.NONE) {
-						getAggregator().append(reportLine);
-					} else {
-						billingData.add(getAdapterOut().writeRow(reportLine));
-						getCurrentStatistics().incrRowWritten();
-					}
-				}
-
-				if (getAggregate() != AggregateGranularity.NONE) {
-					for (int i = 0; i < getAggregator().size(); i++) {
-						billingData.add(getAdapterOut().writeRow(getAggregator().get(i)));
-						getCurrentStatistics().incrRowWritten();
-					}
-				}
-			}
-		} catch (GenericException e) {
-			close(true);
-			if (getCurrentStatistics() != null) {
-				getCurrentStatistics().stop();
-			}
-			throw e;
-		} catch (Exception e) {
-			close(true);
-			if (getCurrentStatistics() != null) {
-				getCurrentStatistics().stop();
-			}
-			throw new ParseException("Unknown parser error. " + e.getLocalizedMessage(), e);
-		}
-
-		close(false);
-		if (getCurrentStatistics() != null) {
-			getCurrentStatistics().stop();
-		}
-		return billingData;
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ParserStatistics.java b/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ParserStatistics.java
deleted file mode 100644
index 55123a4..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/core/parser/ParserStatistics.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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.core.parser;
-
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-/** Store the statistic of parser processing.
- */
-public class ParserStatistics {
-	/** Name of parsed entry. */
-	private final String entryName;
-	
-	/** Time is milliseconds when parser has been started. */
-	private long timeStartInMillis = 0;
-	
-	/** Parsing time in milliseconds. */
-	private long elapsedTimeInMillis = 0;
-	
-	/** Number of rows read. */
-	private long rowReaded;
-	
-	/** Number of rows skipped. */
-	private long rowSkipped;
-	
-	/** Number of rows filtered. */
-	private long rowFiltered;
-	
-	/** Number of rows parsed. */
-	private long rowParsed;
-	
-	/** Number of rows write. */
-	private long rowWritten;
-	
-	
-	public ParserStatistics(String entryName) {
-		this.entryName = entryName;
-	}
-	
-	public void start() {
-		timeStartInMillis = System.currentTimeMillis();
-		elapsedTimeInMillis = 0;
-		rowReaded = 0;
-		rowSkipped = 0;
-		rowFiltered = 0;
-		rowParsed = 0;
-		rowWritten = 0;
-	}
-	
-	public void stop() {
-		if (timeStartInMillis != 0) {
-			elapsedTimeInMillis = System.currentTimeMillis() - timeStartInMillis;
-			timeStartInMillis = 0;
-		}
-	}
-	
-	
-	/** Return the name of parsed entry. */
-	public String getEntryName() {
-		return entryName;
-	}
-	
-	/** Return the elapsed time in milliseconds of initializing, reading, filtering, parsing and writing operations. */
-	public long getElapsedTime() {
-		return (elapsedTimeInMillis != 0 ?
-					elapsedTimeInMillis :
-					timeStartInMillis == 0 ? 0 : System.currentTimeMillis() - timeStartInMillis);
-	}
-	
-	/** Return the number of rows read. */
-	public long getRowReaded() {
-		return rowReaded;
-	}
-	
-	/** Return the number of rows skipped. */
-	public long getRowSkipped() {
-		return rowSkipped;
-	}
-	
-	/** Return the number of rows filtered. */
-	public long getRowFiltered() {
-		return rowFiltered;
-	}
-	
-	/** Return the number of rows parsed. */
-	public long getRowParsed() {
-		return rowParsed;
-	}
-	
-	/** Return the number of rows write. */
-	public long getRowWritten() {
-		return rowWritten;
-	}
-	
-	/** Increment the number of rows read. */
-	public void incrRowReaded() {
-		rowReaded++;
-	}
-	
-	/** Increment the number of rows skipped. */
-	public void incrRowSkipped() {
-		rowSkipped++;
-	}
-	
-	/** Increment the number of rows filtered. */
-	public void incrRowFiltered() {
-		rowFiltered++;
-	}
-	
-	/** Increment the number of rows parsed. */
-	public void incrRowParsed() {
-		rowParsed++;
-	}
-	
-	/** Increment the number of rows write. */
-	public void incrRowWritten() {
-		rowWritten++;
-	}
-	
-
-	public ToStringHelper toStringHelper(Object self) {
-    	return MoreObjects.toStringHelper(self)
-    			.add("entryName", entryName)
-    			.add("elapsedTime", getElapsedTime())
-    			.add("rowReaded", rowReaded)
-    			.add("rowSkipped", rowSkipped)
-    			.add("rowFiltered", rowFiltered)
-    			.add("rowParsed", rowParsed)
-    			.add("rowWritten", rowWritten);
-    }
-	
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/logging/AppenderBase.java b/services/billing-aws/src/main/java/com/epam/dlab/logging/AppenderBase.java
deleted file mode 100644
index 55e5159..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/logging/AppenderBase.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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.logging;
-
-import java.util.TimeZone;
-
-import com.epam.dlab.exceptions.InitializationException;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import ch.qos.logback.classic.Logger;
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.OutputStreamAppender;
-
-/** Abstract class provides base configuration for the log appenders.
- */
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
-public abstract class AppenderBase {
-
-	/** Log format pattern. */
-	private final String logFormatPattern = "%-5p [%d{ISO8601," + TimeZone.getDefault().getID() + "}] %c: %m%n%rEx";
-	
-	/** Perform configure of appender.
-	 * @param context the context of logger.
-	 */
-	public abstract void configure(LoggerContext context) throws InitializationException;
-	
-	/** Perform the base configure of appender.
-	 * @param context the context of logger.
-	 * @param appenderName the name of appender.
-	 * @param appender the class instance of appender.
-	 */
-	public void configure(LoggerContext context, String appenderName, OutputStreamAppender<ILoggingEvent> appender) {
-        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
-        encoder.setPattern(logFormatPattern);
-        encoder.setContext(context);
-        encoder.start();
-
-        appender.setContext(context);
-        appender.setName(appenderName);
-        appender.setEncoder(encoder);
-        appender.start();
-
-        Logger logger = context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
-        logger.addAppender(appender);
-        logger.setAdditive(true);
-	}
-
-	/** Return the name of type for appender. */
-	@JsonIgnore
-	public String getType() {
-		Class<? extends AppenderBase> clazz = this.getClass();
-		return (clazz.isAnnotationPresent(JsonTypeName.class) ?
-				clazz.getAnnotation(JsonTypeName.class).value() : clazz.getName());
-	}
-	
-	
-	/** Returns a string representation of the object.
-	 * @param self the object to generate the string for (typically this), used only for its class name.
-	 */
-	public ToStringHelper toStringHelper(Object self) {
-    	return MoreObjects.toStringHelper(self)
-    			.add("type",  getType());
-    }
-    
-    @Override
-    public String toString() {
-    	return toStringHelper(this)
-    			.toString();
-    }
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/logging/AppenderConsole.java b/services/billing-aws/src/main/java/com/epam/dlab/logging/AppenderConsole.java
deleted file mode 100644
index 780802f..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/logging/AppenderConsole.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.logging;
-
-import com.epam.dlab.exceptions.InitializationException;
-import com.fasterxml.jackson.annotation.JsonClassDescription;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.ConsoleAppender;
-
-/** Console appender for logging.
- */
-@JsonTypeName("console")
-@JsonClassDescription(
-	"Console log appender.\n" +
-	"Output log data to console. Does not have any properties.\n" +
-	"  - type: console"
-	)
-public class AppenderConsole extends AppenderBase {
-	
-	@Override
-    public void configure(LoggerContext context)  throws InitializationException {
-    	super.configure(context, "console-appender", new ConsoleAppender<ILoggingEvent>());
-    }
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/logging/AppenderFile.java b/services/billing-aws/src/main/java/com/epam/dlab/logging/AppenderFile.java
deleted file mode 100644
index e35fbaf..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/logging/AppenderFile.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * 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.logging;
-
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.CoreConstants;
-import ch.qos.logback.core.FileAppender;
-import ch.qos.logback.core.rolling.DefaultTimeBasedFileNamingAndTriggeringPolicy;
-import ch.qos.logback.core.rolling.RollingFileAppender;
-import ch.qos.logback.core.rolling.TimeBasedFileNamingAndTriggeringPolicy;
-import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
-import com.epam.dlab.exceptions.InitializationException;
-import com.fasterxml.jackson.annotation.JsonClassDescription;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-
-/** File appender for logging. Support rolling files and archiving.
- */
-@JsonTypeName("file")
-@JsonClassDescription(
-	"File log appender.\n" + 
-	"Output log data to the file, if property archive is set to true then rolling\n" +
-	"mode is enabled. If archivedLogFilenamePattern ends with .gz or .zip extension\n" +
-	"then old log file will be compressed.\n" +
-	"  - type: file\n" +
-	"    currentLogFilename: <[path/]filename.log>  - pattern for log file naming.\n" +
-	"    [archive: <true | false>]                  - rolling log files or none.\n" +
-	"    [archivedLogFilenamePattern: <[path/]filename-%d{yyyy-MM-dd}.log[.gz | .zip]>]\n" +
-	"                                               - pattern for naming the archive log\n" +
-	"                                                 files.\n" +
-	"    [archivedFileCount: <number_of_days>]      - number of archive log file history."
-	)
-public class AppenderFile extends AppenderBase {
-
-	/** The name of current log file. */
-	@Valid
-    @NotNull
-    @JsonProperty
-    private String currentLogFilename;
-
-	/** Flag for archive of old files. */
-    @Valid
-    @JsonProperty
-    private boolean archive = false;
-    
-    /** Pattern for naming archive files. The compression mode depending on last
-	 * letters of the fileNamePatternStr. Patterns ending with .gz imply GZIP
-	 * compression, endings with '.zip' imply ZIP compression. Otherwise and by
-	 * default, there is no compression. */
-    @Valid
-    @JsonProperty
-    private String archivedLogFilenamePattern;
-    
-    /** The maximum number of archive files to keep.. */
-    @Valid
-    @JsonProperty
-    private int archivedFileCount = CoreConstants.UNBOUND_HISTORY;
-    
-    
-    /** Return the name of current log file. */
-    public String getCurrentLogFilename() {
-    	return currentLogFilename;
-    }
-    
-    /** Set the name of current log file. */
-    public void setCurrentLogFilename(String currentLogFilename) {
-    	this.currentLogFilename = currentLogFilename;
-    }
-    
-    /** Return the flag for archive of old files. */
-    public boolean getArchive() {
-    	return archive;
-    }
-    
-    /** Set the flag for archive of old files. */
-    public void setArchive(boolean archive) {
-    	this.archive = archive;
-    }
-    
-    /** Return the pattern for naming archive files. */
-    public String getArchivedLogFilenamePattern() {
-    	return archivedLogFilenamePattern;
-    }
-    
-    /** Set pattern for naming archive files. The compression mode depending on last
-	 * letters of the fileNamePatternStr. Patterns ending with .gz imply GZIP
-	 * compression, endings with '.zip' imply ZIP compression. Otherwise and by
-	 * default, there is no compression.
-	 * For example,
-	 * /logs/application-%d{yyyy-MM-dd}.log.gz
-	 */
-    public void setArchivedLogFilenamePattern(String archivedLogFilenamePattern) {
-    	this.archivedLogFilenamePattern = archivedLogFilenamePattern;
-    }
-    
-    /** Return the maximum number of archive files to keep.. */
-    public int getArchivedFileCount() {
-    	return archivedFileCount;
-    }
-    
-    /** Set the maximum number of archive files to keep.. */
-    public void setArchivedFileCount(int archivedFileCount) {
-    	this.archivedFileCount = archivedFileCount;
-    }
-    
-    
-    @Override
-    public void configure(LoggerContext context) throws InitializationException {
-    	if (currentLogFilename == null || currentLogFilename.trim().isEmpty()) {
-    		throw new InitializationException("Configuration property logging.appenders.currentLogFilename cannot be null.");
-    	}
-    	super.configure(context, "file-appender", (archive ? getRollingFileAppender(context) : getFileAppender()));
-    }
-
-    /** Create and return synchronous the file appender. 
-     */
-	private FileAppender<ILoggingEvent> getFileAppender() {
-		FileAppender<ILoggingEvent> appender = new FileAppender<>();
-		appender.setFile(currentLogFilename);
-		appender.setAppend(true);
-		return appender;
-	}
-	
-    /** Create and return synchronous the rolling file appender.
-     * @param context the context of logger. 
-     */
-	private RollingFileAppender<ILoggingEvent> getRollingFileAppender(LoggerContext context) throws InitializationException {
-		if (archivedLogFilenamePattern == null || archivedLogFilenamePattern.trim().isEmpty()) {
-			throw new InitializationException("Configuration property logging.appenders.archivedLogFilenamePattern cannot be null.");
-		}
-		RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();
-		appender.setFile(currentLogFilename);
-		appender.setAppend(true);
-
-		TimeBasedFileNamingAndTriggeringPolicy<ILoggingEvent> triggerPolicy = new DefaultTimeBasedFileNamingAndTriggeringPolicy<>();
-		triggerPolicy.setContext(context);
-
-		TimeBasedRollingPolicy<ILoggingEvent> rollPolicy = new TimeBasedRollingPolicy<>();
-		rollPolicy.setContext(context);
-		rollPolicy.setParent(appender);
-		rollPolicy.setFileNamePattern(archivedLogFilenamePattern);
-        rollPolicy.setMaxHistory(archivedFileCount);
-        rollPolicy.setTimeBasedFileNamingAndTriggeringPolicy(triggerPolicy);
-        rollPolicy.start();
-        appender.setRollingPolicy(rollPolicy);
-        
-		return appender;
-	}
-
-	
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("currentLogFilename", currentLogFilename)
-				.add("archive", archive)
-				.add("archivedLogFilenamePattern", archivedLogFilenamePattern)
-				.add("archivedFileCount", archivedFileCount);
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/module/AdapterConsole.java b/services/billing-aws/src/main/java/com/epam/dlab/module/AdapterConsole.java
deleted file mode 100644
index bb92e9b..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/module/AdapterConsole.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.module;
-
-import com.epam.dlab.core.AdapterBase;
-import com.epam.dlab.core.parser.CommonFormat;
-import com.epam.dlab.exceptions.AdapterException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.fasterxml.jackson.annotation.JsonClassDescription;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-import org.bson.Document;
-
-import java.util.List;
-
-/**
- * The adapter for console output.
- */
-@JsonTypeName(ModuleName.ADAPTER_CONSOLE)
-@JsonClassDescription(
-		"Console adapter.\n" +
-				"Output data to console. Can be used for AdapterOut only.\n" +
-				"  - type: " + ModuleName.ADAPTER_CONSOLE + "\n" +
-				"    [writeHeader: <true | false>]  - write header of data to the adapterOut."
-)
-public class AdapterConsole extends AdapterBase {
-
-	/**
-	 * Default constructor for deserialization.
-	 */
-	public AdapterConsole() {
-	}
-
-	/**
-	 * Instantiate adapter for reading or writing.
-	 *
-	 * @param mode the mode of adapter.
-	 */
-	public AdapterConsole(Mode mode) {
-		super(mode);
-	}
-
-
-	@Override
-	public void open() throws AdapterException {
-		if (getMode() != Mode.WRITE) {
-			throw new AdapterException("Mode of " + getType() + " adapter may be " + Mode.WRITE + " only.");
-		}
-	}
-
-	@Override
-	public void close() throws AdapterException {
-		// Nothing to do
-	}
-
-	@Override
-	public String getEntryName() {
-		return "console";
-	}
-
-	@Override
-	public String readLine() throws AdapterException {
-		throw new AdapterException("Unimplemented method called.");
-	}
-
-	@Override
-	public void writeHeader(List<String> header) {
-		System.out.println(CommonFormat.rowToString(header));
-	}
-
-	@Override
-	public Document writeRow(ReportLine row) {
-		System.out.println(CommonFormat.rowToString(row));
-		return null;
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/module/AdapterFile.java b/services/billing-aws/src/main/java/com/epam/dlab/module/AdapterFile.java
deleted file mode 100644
index 38e36d8..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/module/AdapterFile.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * 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.module;
-
-import com.epam.dlab.core.AdapterBase;
-import com.epam.dlab.core.parser.CommonFormat;
-import com.epam.dlab.exceptions.AdapterException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.fasterxml.jackson.annotation.JsonClassDescription;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import org.bson.Document;
-
-import javax.validation.constraints.NotNull;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.List;
-
-/**
- * The adapter for file system.
- */
-@JsonTypeName(ModuleName.ADAPTER_FILE)
-@JsonClassDescription(
-		"File adapter.\n" +
-				"Read source or write converted data to the file.\n" +
-				"  - type: " + ModuleName.ADAPTER_FILE + "\n" +
-				"    [writeHeader: <true | false>]  - write header of data to the adapterOut.\n" +
-				"    file: <filename>               - the name of file."
-)
-public class AdapterFile extends AdapterBase {
-
-	/**
-	 * The name of file.
-	 */
-	@NotNull
-	@JsonProperty
-	private String file;
-	/**
-	 * Reader for adapter.
-	 */
-	@JsonIgnore
-	private BufferedReader reader;
-	/**
-	 * Writer for adapter.
-	 */
-	@JsonIgnore
-	private BufferedWriter writer;
-
-	/**
-	 * Return the name of file.
-	 */
-	public String getFile() {
-		return file;
-	}
-
-	/**
-	 * Set the name of file.
-	 */
-	public void setFile(String file) {
-		this.file = file;
-	}
-
-	@Override
-	public void open() throws AdapterException {
-		try {
-			if (getMode() == Mode.READ) {
-				reader = new BufferedReader(new FileReader(file));
-			} else if (getMode() == Mode.WRITE) {
-				writer = new BufferedWriter(new FileWriter(file));
-			} else {
-				throw new AdapterException("Mode of adapter unknown or not defined. Set mode to " + Mode.READ + " or " + Mode.WRITE + ".");
-			}
-		} catch (Exception e) {
-			throw new AdapterException("Cannot open file " + file + ". " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	@Override
-	public void close() throws AdapterException {
-		if (reader != null) {
-			try {
-				reader.close();
-			} catch (IOException e) {
-				throw new AdapterException("Cannot close file " + file + ". " + e.getLocalizedMessage(), e);
-			} finally {
-				reader = null;
-			}
-		}
-
-		if (writer != null) {
-			try {
-				writer.close();
-			} catch (IOException e) {
-				throw new AdapterException("Cannot close file " + file + ". " + e.getLocalizedMessage(), e);
-			} finally {
-				writer = null;
-			}
-		}
-	}
-
-	@Override
-	public String getEntryName() {
-		return getFile();
-	}
-
-	@Override
-	public String readLine() throws AdapterException {
-		try {
-			return reader.readLine();
-		} catch (IOException e) {
-			throw new AdapterException("Cannot read file " + file + ". " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	@Override
-	public void writeHeader(List<String> header) throws AdapterException {
-		try {
-			writer.write(CommonFormat.rowToString(header));
-			writer.write(System.lineSeparator());
-		} catch (IOException e) {
-			throw new AdapterException("Cannot write file " + file + ". " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	@Override
-	public Document writeRow(ReportLine row) throws AdapterException {
-		try {
-			writer.write(CommonFormat.rowToString(row));
-			writer.write(System.lineSeparator());
-		} catch (IOException e) {
-			throw new AdapterException("Cannot write file " + file + ". " + e.getLocalizedMessage(), e);
-		}
-		return null;
-	}
-
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("file", file);
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/module/ModuleName.java b/services/billing-aws/src/main/java/com/epam/dlab/module/ModuleName.java
deleted file mode 100644
index 58a31b8..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/module/ModuleName.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.module;
-
-/** Names of billing tool modules.
- */
-public class ModuleName {
-	public static final String ADAPTER_CONSOLE = "console";
-	public static final String ADAPTER_AGG_CONSOLE = "aggConsole";
-	public static final String ADAPTER_FILE = "file";
-	public static final String ADAPTER_S3_FILE = "s3file";
-	public static final String ADAPTER_MONGO_DLAB = "mongodlab";
-	public static final String PARSER_CSV = "csv";
-	public static final String FILTER_AWS = "aws";
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/module/ParserCsv.java b/services/billing-aws/src/main/java/com/epam/dlab/module/ParserCsv.java
deleted file mode 100644
index 7b3d249..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/module/ParserCsv.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * 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.module;
-
-import com.epam.dlab.core.parser.ParserByLine;
-import com.epam.dlab.exceptions.AdapterException;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.exceptions.ParseException;
-import com.fasterxml.jackson.annotation.JsonClassDescription;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.validation.constraints.NotNull;
-import java.util.ArrayList;
-import java.util.List;
-
-/** Parse CSV format to common CSV format.
- */
-@JsonTypeName(ModuleName.PARSER_CSV)
-@JsonClassDescription(
-	"CSV parser.\n" +
-	"Parse source CSV format to common billing report.\n" +
-	"  - type: " + ModuleName.PARSER_CSV + "\n" +
-	"    [dataFile: <filename>]           - the file name to store working data of parser.]\n" +
-	"    [columnStartDate: <column_name>] - the name of source column with date of data.]\n" +
-	"    [columnMapping: >-\n" +
-    "                    <targetColumn1=sourceColumnX;targetColumn2=sourceColumnY; ...;\n" +
-    "                     tags=sourceColumnK,...,sourceColumnN>]\n" +
-    "                                  - columns mapping to target from source columns.\n" +
-    "                                    Know target columns: dlab_id, user,\n" +
-    "                                    usage_date, product, usage_type, usage, cost,\n" +
-    "                                    currency_code, resource_id, tags.\n" +
-	"    [whereCondition: >-\n" +
-    "                    <(source_columnX > 0.0 || source_columnY == 'string') &&\n" +
-    "                     source_columnZ != 2016>]\n" +
-    "                                  - where condition for filtering the source data,\n" +
-    "                                    see http://commons.apache.org/proper/commons-jexl/reference/syntax.html#Operators\n" +
-    "                                    for detais.\n" +
-	"    [aggregate: <none | month | day>] - how to aggregate the data.\n" +
-	"    [headerLineNo: <number>]          - the number of header line in source data.\n" +
-	"    [skipLines: <numbber>]            - the number of line which will be skipped\n" +
-	"                                        (include header).\n" +
-	"    [fieldSeparator: <char>]          - char for separate field names and values.\n" +
-	"    [fieldTerminator: <char>]         - char for terminate field names and values.\n" +
-	"    [escapeChar: <char>]              - escape char.\n" +
-	"    [decimalSeparator: <char>]        - char for decimal sign.\n" +
-	"    [groupingSeparator: <char>]       - char for thousands separator.\n"
-	)
-public class ParserCsv extends ParserByLine {
-	private static final Logger LOGGER = LoggerFactory.getLogger(ParserCsv.class);
-
-	/** Character for separate field names and values. */
-	public static final char FIELD_SEPARATOR_DEFAULT = ',';
-	
-	/** Character for termination field names and values. */
-	public static final char FIELD_DELIMITER_DEFAULT = '"';
-	
-	/** Escape character. */
-	public static final char ESCAPE_CHAR_DEFAULT = '\\';
-	
-
-	/** Character for separate field names and values. */
-	@NotNull
-	@JsonProperty
-	private char fieldSeparator = FIELD_SEPARATOR_DEFAULT;
-
-	/** Character for termination field names and values. */
-	@NotNull
-	@JsonProperty
-	private char fieldTerminator = FIELD_DELIMITER_DEFAULT;
-	
-	/** Escape character. */
-	@NotNull
-	@JsonProperty
-	private char escapeChar = ESCAPE_CHAR_DEFAULT;
-
-	/** The number of line that contain the header of data.*/
-	@JsonProperty
-	private int headerLineNo = 0;
-
-	/** The number of line which will be skipped (include header).*/
-	@JsonProperty
-	private int skipLines = 0;
-	
-
-	/** Return the character for separate field names and values. */
-	public char getFieldSeparator() {
-		return fieldSeparator;
-	}
-	
-	/** Set the character for separate field names and values. */
-	public void setFieldSeparator(char fieldSeparator) {
-		this.fieldSeparator = fieldSeparator;
-	}
-	
-	/** Return the character for termination field names and values. */
-	public char getFieldTerminator() {
-		return fieldTerminator;
-	}
-	
-	/** Set the character for termination field names and values. */
-	public void setFieldTerminator(char fieldTerminator) {
-		this.fieldTerminator = fieldTerminator;
-	}
-	
-	/** Return the escape character. */
-	public char getEscapeChar() {
-		return escapeChar;
-	}
-	
-	/** Set the escape character. */
-	public void setEscapeChar(char escapeChar) {
-		this.escapeChar = escapeChar;
-	}
-	
-	/** Return the number of line that contain the header of data.*/
-	public int getHeaderLineNo() {
-		return headerLineNo;
-	}
-	
-	/** Set the number of line that contain the header of data.*/
-	public void setHeaderLineNo(int headerLineNo) {
-		this.headerLineNo = headerLineNo;
-	}
-	
-	/** Return the number of line which will be skipped (include header).*/
-	public int getSkipLines() {
-		return skipLines;
-	}
-
-	/** Set the number of line which will be skipped (include header).*/
-	public void setSkipLines(int skipLines) {
-		this.skipLines = skipLines;
-	}
-
-	
-	@Override
-	public void initialize() throws InitializationException { }
-	
-	@Override
-	public List<String> parseHeader() throws AdapterException, ParseException {
-		String line = null;
-		List<String> header = null;
-		
-		if (headerLineNo > 0) {
-    		while(getCurrentStatistics().getRowReaded() < headerLineNo) {
-    			if ((line = getNextRow()) == null) {
-    				return null;
-    			}
-    			getCurrentStatistics().incrRowSkipped();
-    		}
-    		header = parseRow(line);
-    	}
-    	
-    	while (getCurrentStatistics().getRowReaded() < skipLines) {
-    		if (getNextRow() == null) {
-    			break;
-    		}
-    		getCurrentStatistics().incrRowSkipped();
-    	}
-    	
-    	return header;
-	}
-	
-	
-	/** Construct the exception.
-	 * @param message the error message.
-	 * @param pos the position in the parsed line.
-	 * @param sourceLine the parsed line.
-	 * @return ParseException
-	 */
-	private ParseException getParseException(String message, int pos, String sourceLine) {
-		String s = String.format("%s at pos %d in line: ", message, pos);
-		LOGGER.error(s + sourceLine);
-		LOGGER.error(StringUtils.repeat(' ', s.length() + pos - 1) + '^');
-		return new ParseException(s + sourceLine);
-	}
-
-	@Override
-	public List<String> parseRow(String line) throws ParseException {
-		int realPos = 0;
-		int pos = 0;
-		boolean isDelimiter = false;
-		StringBuilder sb = new StringBuilder(line);
-		List<String> row = new ArrayList<>();
-
-		while (pos < sb.length()) {
-			char c = sb.charAt(pos);
-			if (c == escapeChar) {
-				realPos++;
-				pos++;
-				if (pos == sb.length()) {
-					throw getParseException("Invalid escape char", realPos, line);
-				}
-				sb.delete(pos - 1, pos);
-				realPos++;
-			} else if (c == fieldTerminator) {
-				realPos++;
-				if (isDelimiter) {
-					realPos++;
-					pos++;
-					if (pos == sb.length()) {
-						sb.delete(pos - 1, pos);
-						break;
-					}
-					if (sb.charAt(pos) == fieldSeparator) {
-						row.add(sb.substring(0, pos - 1));
-						sb.delete(0, pos + 1);
-						pos = 0;
-						isDelimiter = false;
-						continue;
-					}
-					throw getParseException("Invalid field delimiter", realPos, line);
-				}
-				
-				if (pos != 0) {
-					throw getParseException("Unterminated field", realPos, line);
-				}
-				sb.delete(0, 1);
-				isDelimiter = true;
-				continue;
-			} else if (c == fieldSeparator) {
-				realPos++;
-				if (isDelimiter) {
-					pos++;
-					continue;
-				}
-				row.add(sb.substring(0, pos));
-				sb.delete(0, pos + 1);
-				pos = 0;
-			} else {
-				realPos++;
-				pos++;
-			}
-		}
-		row.add(sb.toString());
-		
-		return row;
-	}
-	
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-    	return super.toStringHelper(self)
-    	        .add("fieldSeparator", fieldSeparator)
-    	        .add("fieldTerminator", fieldTerminator)
-    	        .add("escapeChar", escapeChar)
-    	        .add("headerLineNo", headerLineNo)
-    	        .add("skipLines", skipLines);
-    }
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/module/aws/AdapterS3File.java b/services/billing-aws/src/main/java/com/epam/dlab/module/aws/AdapterS3File.java
deleted file mode 100644
index 68a5d41..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/module/aws/AdapterS3File.java
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * 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.module.aws;
-
-import com.amazonaws.auth.BasicAWSCredentials;
-import com.amazonaws.services.s3.AmazonS3;
-import com.amazonaws.services.s3.AmazonS3Client;
-import com.amazonaws.services.s3.model.GetObjectRequest;
-import com.amazonaws.services.s3.model.S3Object;
-import com.epam.dlab.core.AdapterBase;
-import com.epam.dlab.exceptions.AdapterException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.epam.dlab.module.ModuleName;
-import com.fasterxml.jackson.annotation.JsonClassDescription;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import org.bson.Document;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.validation.constraints.NotNull;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.Date;
-import java.util.List;
-
-/**
- * The adapter for S3 file system of Amazon.
- */
-@JsonTypeName(ModuleName.ADAPTER_S3_FILE)
-@JsonClassDescription(
-		"Amazon S3 file system adapter.\n" +
-				"Read source or write converted data to the file in Amazon S3 bucket.\n" +
-				"  - type: " + ModuleName.ADAPTER_S3_FILE + "\n" +
-				"    [writeHeader: <true | false>]   - write header of data to the adapterOut.\n" +
-				"    bucket: <bucketname>            - the name of S3 bucket.\n" +
-				"    path: <path>                    - the path to the report or empty if used the root folder.\n" +
-				"    accountId: <AWS account number> - the account number, see for details\n" +
-				"                                      \"Detailed billing report with resources and tags\"\n" +
-				"                                      http://docs.aws.amazon" +
-				".com/awsaccountbilling/latest/aboutv2/billing-reports.html#detailed-report-with-resources-tags\n" +
-				"    [accessKeyId: <string>]         - Amazon access key ID.\n" +
-				"    [secretAccessKey: <string>]     - Amazon secret access key."
-)
-public class AdapterS3File extends AdapterBase {
-	/**
-	 * Name of key for the last loaded file.
-	 */
-	public static final String DATA_KEY_LAST_LOADED_FILE = "AdapterS3File_lastLoadedFile";
-	/**
-	 * Name of key for the modification date of loaded file.
-	 */
-	public static final String DATA_KEY_LAST_MODIFICATION_DATE = "AdapterS3File_lastModifyDate";
-	private static final Logger LOGGER = LoggerFactory.getLogger(AdapterS3File.class);
-	private static final String CANNOT_READ_FILE_FORMAT = "Cannot read file %s. %s";
-	private static final String DELIMITER = "/";
-
-	/**
-	 * The name of bucket.
-	 */
-	@NotNull
-	@JsonProperty
-	private String bucket;
-
-	/**
-	 * The path to report.
-	 */
-	@JsonProperty
-	private String path;
-
-	/**
-	 * AWS account number.
-	 */
-	@NotNull
-	@JsonProperty
-	private String accountId;
-
-	/**
-	 * Access key ID for Amazon Web Services.
-	 */
-	@JsonProperty
-	private String accessKeyId;
-
-	/**
-	 * Secret key for Amazon Web Services.
-	 */
-	@JsonProperty
-	private String secretAccessKey;
-
-	@JsonProperty
-	private boolean awsJobEnabled;
-	/**
-	 * List of report files for loading.
-	 */
-	@JsonIgnore
-	private List<String> filelist = null;
-	/**
-	 * Index of current report file.
-	 */
-	@JsonIgnore
-	private int currentFileIndex = -1;
-	/**
-	 * Index of current report file.
-	 */
-	@JsonIgnore
-	private String entryName = null;
-	/**
-	 * Amazon S3 client.
-	 */
-	@JsonIgnore
-	private AmazonS3 clientS3 = null;
-	/**
-	 * Amazon S3 client.
-	 */
-	@JsonIgnore
-	private Date lastModificationDate = null;
-	/**
-	 * File input stream.
-	 */
-	@JsonIgnore
-	private InputStream fileInputStream = null;
-	/**
-	 * Reader for adapter.
-	 */
-	@JsonIgnore
-	private BufferedReader reader = null;
-
-	/**
-	 * Return the name of bucket.
-	 */
-	public String getBucket() {
-		return bucket;
-	}
-
-	/**
-	 * Set the name of bucket.
-	 */
-	public void setBucket(String bucket) {
-		this.bucket = bucket;
-	}
-
-	/**
-	 * Return the path to report.
-	 */
-	public String getPath() {
-		return path;
-	}
-
-	/**
-	 * Set the path to report.
-	 */
-	public void setPath(String path) {
-		this.path = path;
-	}
-
-	/**
-	 * Return the AWS account number.
-	 */
-	public String getAccountId() {
-		return accountId;
-	}
-
-	/**
-	 * Set the AWS account number.
-	 */
-	public void setAccountId(String accountId) {
-		this.accountId = accountId;
-	}
-
-	/**
-	 * Return the access key ID for Amazon Web Services.
-	 */
-	public String getAccessKeyId() {
-		return this.accessKeyId;
-	}
-
-	/**
-	 * Set the access key ID for Amazon Web Services.
-	 */
-	public void setAccessKeyId(String accessKeyId) {
-		this.accessKeyId = accessKeyId;
-	}
-
-	/**
-	 * Return the secret key for Amazon Web Services.
-	 */
-	public String getSecretAccessKey() {
-		return this.secretAccessKey;
-	}
-
-	/**
-	 * Set the secret key for Amazon Web Services.
-	 */
-	public void setSecretAccessKey(String secretAccessKey) {
-		this.secretAccessKey = secretAccessKey;
-	}
-
-	@Override
-	public void open() throws AdapterException {
-		LOGGER.debug("Adapter S3 will be opened for {}", getMode());
-		if (getMode() == Mode.READ) {
-			setLastModificationDate();
-			clientS3 = getAmazonClient();
-			S3FileList s3files = new S3FileList(awsJobEnabled, bucket, getModuleData());
-			filelist = s3files.getFiles(clientS3);
-			currentFileIndex = (filelist.isEmpty() ? -1 : 0);
-			fileInputStream = null;
-			reader = null;
-			entryName = null;
-			openNextEntry();
-			LOGGER.debug("Adapter S3 has been opened");
-		} else if (getMode() == Mode.WRITE) {
-			throw new AdapterException("Unsupported mode " + Mode.WRITE + ".");
-		} else {
-			throw new AdapterException("Mode of adapter unknown or not defined. Set mode to " + Mode.READ + ".");
-		}
-	}
-
-	@Override
-	public boolean hasMultyEntry() {
-		return true;
-	}
-
-	@Override
-	public boolean openNextEntry() throws AdapterException {
-		String filename = getCurrentFileName();
-		if (filename == null) {
-			if (filelist.isEmpty()) {
-				final String reportPath = path == null ? bucket : bucket + DELIMITER + path;
-				LOGGER.debug("New report files in bucket folder {} not found", reportPath);
-			}
-			return false;
-		}
-		entryName = filename;
-		LOGGER.debug("Open a next entry in file {}", filename);
-		reader = new BufferedReader(new InputStreamReader(getFileStream()));
-		try {
-			getModuleData().setId(filename);
-			getModuleData().setModificationDate(lastModificationDate);
-			getModuleData().set(DATA_KEY_LAST_LOADED_FILE, filename);
-			getModuleData().set(DATA_KEY_LAST_MODIFICATION_DATE, lastModificationDate);
-			getModuleData().store();
-		} catch (Exception e) {
-			throw new AdapterException(e.getLocalizedMessage(), e);
-		}
-		currentFileIndex++;
-		return false;
-	}
-
-	@Override
-	public boolean hasEntryData() {
-		return (reader != null);
-	}
-
-	@Override
-	public void close() throws AdapterException {
-		closeFile(getCurrentFileName());
-	}
-
-	@Override
-	public String getEntryName() {
-		return entryName;
-	}
-
-	@Override
-	public String readLine() throws AdapterException {
-		try {
-			return reader.readLine();
-		} catch (IOException e) {
-			throw new AdapterException(String.format(CANNOT_READ_FILE_FORMAT, getCurrentFileName(), e
-					.getLocalizedMessage()), e);
-		}
-	}
-
-	@Override
-	public void writeHeader(List<String> header) throws AdapterException {
-		throw new AdapterException("Unimplemented method.");
-	}
-
-	@Override
-	public Document writeRow(ReportLine row) throws AdapterException {
-		throw new AdapterException("Unimplemented method.");
-	}
-
-	/**
-	 * Return the current file name.
-	 */
-	public String getCurrentFileName() {
-		return (filelist == null || currentFileIndex < 0 || currentFileIndex >= filelist.size() ? null : filelist.get
-				(currentFileIndex));
-	}
-
-	/**
-	 * Creates and returns the Amazon client, as well as checks bucket existence.
-	 *
-	 * @throws AdapterException
-	 */
-	private AmazonS3 getAmazonClient() throws AdapterException {
-		AmazonS3 s3 = (accessKeyId == null ?
-				new AmazonS3Client() :
-				new AmazonS3Client(new BasicAWSCredentials(accessKeyId, secretAccessKey)));
-
-		if (!s3.doesBucketExist(bucket)) {
-			throw new AdapterException("Bucket \"" + bucket + "\" does not exist.");
-		}
-
-		return s3;
-	}
-
-	/**
-	 * Open the source file and return reader.
-	 *
-	 * @throws AdapterException
-	 */
-	private InputStream getFileStream() throws AdapterException {
-		try {
-			GetObjectRequest request = new GetObjectRequest(bucket, getCurrentFileName());
-			S3Object object = clientS3.getObject(request);
-			lastModificationDate = object.getObjectMetadata().getLastModified();
-			return object.getObjectContent();
-		} catch (Exception e) {
-			throw new AdapterException("Cannot open file " + bucket + DELIMITER + getCurrentFileName() + ". " + e
-					.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Return the modification date of loaded file.
-	 *
-	 * @throws AdapterException
-	 */
-	private void setLastModificationDate() throws AdapterException {
-		try {
-			lastModificationDate = getModuleData().getDate(DATA_KEY_LAST_MODIFICATION_DATE);
-		} catch (Exception e) {
-			throw new AdapterException("Cannot get the last modification date for report. " + e.getLocalizedMessage(),
-					e);
-		}
-	}
-
-	/**
-	 * Close a zip file.
-	 *
-	 * @param filename file name.
-	 * @throws AdapterException
-	 */
-	private void closeFile(String filename) throws AdapterException {
-		if (fileInputStream != null) {
-			try {
-				fileInputStream.close();
-			} catch (IOException e) {
-				throw new AdapterException("Cannot close file " + filename + ". " + e.getLocalizedMessage(), e);
-			}
-			fileInputStream = null;
-		}
-	}
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("bucket", bucket)
-				.add("path", path)
-				.add("accountId", accountId)
-				.add("accessKeyId", "***")
-				.add("secretAccessKey", "***");
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/module/aws/FilterAWS.java b/services/billing-aws/src/main/java/com/epam/dlab/module/aws/FilterAWS.java
deleted file mode 100644
index 66d3cb9..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/module/aws/FilterAWS.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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.module.aws;
-
-import com.epam.dlab.core.FilterBase;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.epam.dlab.module.ModuleName;
-import com.fasterxml.jackson.annotation.JsonClassDescription;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import javax.validation.constraints.NotNull;
-import java.util.List;
-
-/**
- * Filter and transform the line of AWS detailed billing reports.
- */
-@JsonTypeName(ModuleName.FILTER_AWS)
-@JsonClassDescription(
-		"Amazon Web Services detailed billing reports filter.\n" +
-				"Filter report data and select line item only. Set column projectCode and\n" +
-				"currencyCode to user values.\n" +
-				"  - type: " + ModuleName.FILTER_AWS + "\n" +
-				"    [currencyCode: <string>]    - user value for currencyCode column.\n" +
-				"    [columnDlabTag: <string>]   - name of column tag of DLab resource id.\n" +
-				"    [serviceBaseName: <string>] - DLab's service base name."
-
-)
-public class FilterAWS extends FilterBase {
-
-	/**
-	 * The code of currency.
-	 */
-	@NotNull
-	@JsonProperty
-	private String currencyCode;
-
-	/**
-	 * Name of report column tag of DLab.
-	 */
-	@NotNull
-	@JsonProperty
-	private String columnDlabTag;
-
-	/**
-	 * DLab service base name.
-	 */
-	@NotNull
-	@JsonProperty
-	private String serviceBaseName;
-	private int dlabIdIndex = -1;
-	private String dlabPrefix;
-
-	/**
-	 * Return the code of currency for billing.
-	 */
-	public String getCurrencyCode() {
-		return currencyCode;
-	}
-
-	/**
-	 * Set the code of currency for billing.
-	 */
-	public void setCurrencyCode(String currencyCode) {
-		this.currencyCode = currencyCode;
-	}
-
-	/**
-	 * Return the name of report column tag of DLab.
-	 */
-	public String getColumnDlabTag() {
-		return columnDlabTag;
-	}
-
-	/**
-	 * Set the name of report column tag of DLab.
-	 */
-	public void setDlabTagName(String columnDlabTag) {
-		this.columnDlabTag = columnDlabTag;
-	}
-
-	/**
-	 * Return service base name.
-	 */
-	public String getServiceBaseName() {
-		return serviceBaseName;
-	}
-
-	/**
-	 * Set service base name.
-	 */
-	public void setServiceBaseName(String serviceBaseName) {
-		this.serviceBaseName = serviceBaseName;
-	}
-
-	@Override
-	public void initialize() throws InitializationException {
-		dlabIdIndex = (getColumnDlabTag() == null ? -1 :
-				getParser().getSourceColumnIndexByName(getColumnDlabTag()));
-		dlabPrefix = getServiceBaseName() + ":";
-	}
-
-	@Override
-	public String canParse(String line) {
-		return line;
-	}
-
-	@Override
-	public List<String> canTransform(List<String> row) {
-		if (dlabIdIndex != -1 &&
-				(row.size() <= dlabIdIndex ||
-						!row.get(dlabIdIndex).startsWith(dlabPrefix))) {
-			return null;
-		}
-		return row;
-	}
-
-	@Override
-	public ReportLine canAccept(ReportLine row) {
-		row.setCurrencyCode(currencyCode);
-		return row;
-	}
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("currencyCode", currencyCode)
-				.add("columnDlabTag", columnDlabTag)
-				.add("serviceBaseName", serviceBaseName);
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/module/aws/S3FileList.java b/services/billing-aws/src/main/java/com/epam/dlab/module/aws/S3FileList.java
deleted file mode 100644
index 021497e..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/module/aws/S3FileList.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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.module.aws;
-
-import com.amazonaws.services.s3.AmazonS3;
-import com.amazonaws.services.s3.model.ListObjectsV2Request;
-import com.amazonaws.services.s3.model.ListObjectsV2Result;
-import com.amazonaws.services.s3.model.S3ObjectSummary;
-import com.epam.dlab.core.ModuleData;
-import com.epam.dlab.exceptions.AdapterException;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static java.util.stream.Collectors.mapping;
-import static java.util.stream.Collectors.toList;
-
-/**
- * Create a file listing of reports from AWS bucket.
- * See details in
- * <a href="http://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/billing-reports.html#detailed-report-with-resources-tags">
- * Detailed billing report with resources and tags</a>.
- */
-public class S3FileList {
-
-	/**
-	 * Report suffix without date.
-	 */
-	private static final String REPORT_SUFIX = ".csv";
-	/**
-	 * Date regex for YYYYMMDD
-	 */
-	private static final String DATE_REGEX = "\\d{4}(0?[1-9]|1[012])(0?[1-9]|[12][0-9]|3[01])";
-	private static final String REGEX = String.format("(^.*/.*/%s-%s)/.*/*.\\%s", DATE_REGEX, DATE_REGEX,
-			REPORT_SUFIX);
-
-	/**
-	 * Bucket name.
-	 */
-	private final String bucket;
-
-	/**
-	 * Name of last file which is loaded or <b>null</b> for loading all files in bucket folder.
-	 */
-	private final ModuleData moduleData;
-	private final Pattern reportPattern;
-	private final boolean awsJobEnabled;
-
-
-	/**
-	 * Instantiate file find class.
-	 *
-	 * @param awsJobEnabled
-	 * @param bucket        the name of bucket.
-	 * @param moduleData    data for working module
-	 */
-	public S3FileList(boolean awsJobEnabled, String bucket, ModuleData moduleData) {
-		this.bucket = bucket;
-		this.moduleData = moduleData;
-		this.awsJobEnabled = awsJobEnabled;
-		this.reportPattern = this.awsJobEnabled ? Pattern.compile(REGEX) : Pattern.compile(".*" + REPORT_SUFIX + "$");
-	}
-
-	/**
-	 * Return the list of files for new reports.
-	 *
-	 * @param s3Client the S3 client.
-	 * @return the list of files.
-	 * @throws AdapterException
-	 */
-	public List<String> getFiles(AmazonS3 s3Client) throws AdapterException {
-		final List<S3ObjectSummary> objectSummaries = reportFilesInBillingBucket(s3Client);
-		return awsJobEnabled ? lastFilesPerBillingPeriod(objectSummaries) :
-				objectSummaries.stream().map(S3ObjectSummary::getKey).sorted().collect(toList());
-	}
-
-	private List<S3ObjectSummary> reportFilesInBillingBucket(AmazonS3 s3Client) throws AdapterException {
-		ListObjectsV2Request request = new ListObjectsV2Request()
-				.withBucketName(bucket);
-		ListObjectsV2Result result;
-		List<S3ObjectSummary> objectSummaries = new ArrayList<>();
-		try {
-			do {
-				result = s3Client.listObjectsV2(request);
-				objectSummaries.addAll(notProcessedFiles(result));
-			} while (result.isTruncated());
-		} catch (Exception e) {
-			throw new AdapterException("Cannot get the file listing of bucket \"" + bucket + "*\". " +
-					e.getLocalizedMessage(), e);
-		}
-		return objectSummaries;
-	}
-
-	private List<S3ObjectSummary> notProcessedFiles(ListObjectsV2Result result) {
-		return result.getObjectSummaries()
-				.stream()
-				.filter(this::matchBillingRegexAndWasNotProcessed)
-				.collect(toList());
-	}
-
-	private boolean matchBillingRegexAndWasNotProcessed(S3ObjectSummary o) {
-		return reportPattern.matcher(o.getKey()).matches()
-				&& !moduleData.wasProcessed(o.getKey(), o.getLastModified(),
-				extractDatePrefix(reportPattern, o));
-	}
-
-	/**
-	 * Returns list of files that per billing period
-	 * For particular billing period file with the biggest modification date will be returned
-	 *
-	 * @param objectSummaries amazon s3 objects
-	 * @return list of file names
-	 */
-	protected List<String> lastFilesPerBillingPeriod(List<S3ObjectSummary> objectSummaries) {
-		final Map<String, List<S3ObjectSummary>> months = objectSummaries.stream()
-				.collect(Collectors.groupingBy(o -> extractDatePrefix(reportPattern, o), mapping(o -> o, toList())));
-
-		return months.entrySet()
-				.stream()
-				.flatMap(this::lastFileForBillingPeriod)
-				.sorted()
-				.collect(Collectors.toList());
-	}
-
-	private Stream<? extends String> lastFileForBillingPeriod(Map.Entry<String, List<S3ObjectSummary>> entry) {
-		final List<S3ObjectSummary> assemblyIds = entry.getValue();
-		final S3ObjectSummary lastBillingFile = assemblyIds.stream()
-				.max(Comparator.comparing(S3ObjectSummary::getLastModified))
-				.orElseThrow(() -> new IllegalStateException("AssemblyId does not contains any file"));
-		return assemblyIds.stream()
-				.filter(s -> s.getKey().startsWith(StringUtils.substringBeforeLast(lastBillingFile.getKey(), "/")))
-				.map(S3ObjectSummary::getKey);
-	}
-
-	private String extractDatePrefix(Pattern pattern, S3ObjectSummary o) {
-		final String key = o.getKey();
-		final Matcher matcher = pattern.matcher(key);
-		if (matcher.find() && awsJobEnabled) {
-			return matcher.group(1);
-		} else {
-			return key;
-		}
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/mongo/AdapterMongoDb.java b/services/billing-aws/src/main/java/com/epam/dlab/mongo/AdapterMongoDb.java
deleted file mode 100644
index 7feca95..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/mongo/AdapterMongoDb.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * 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.mongo;
-
-import com.epam.dlab.core.DBAdapterBase;
-import com.epam.dlab.core.aggregate.UsageDataList;
-import com.epam.dlab.exceptions.AdapterException;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.exceptions.ParseException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.epam.dlab.module.ModuleName;
-import com.fasterxml.jackson.annotation.JsonClassDescription;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import com.mongodb.client.MongoCollection;
-import com.mongodb.client.model.UpdateOptions;
-import org.bson.Document;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.TreeSet;
-
-import static com.epam.dlab.mongo.MongoConstants.COLLECTION_SETTINGS;
-import static com.epam.dlab.mongo.MongoConstants.FIELD_SERIVICE_BASE_NAME;
-import static com.mongodb.client.model.Filters.eq;
-
-/**
- * The adapter for file system.
- */
-@JsonTypeName(ModuleName.ADAPTER_MONGO_DLAB)
-@JsonClassDescription(
-		"Mongo DB adapter.\n" +
-				"Write converted data to the Mongo database. Can be used for AdapterOut only.\n" +
-				"  - type: " + ModuleName.ADAPTER_MONGO_DLAB + "\n" +
-				"    host: <host>             - the host name or IP address.\n" +
-				"    port: <port>             - the port number.\n" +
-				"    database: <database>     - the name of database.\n" +
-				"    username: <username>     - the name of user.\n" +
-				"    password: <password>     - the password of user.\n" +
-				"    [bufferSize: <number>]   - the size of buffer, default is 10000 records.\n" +
-				"    [upsert: <false | true>] - if true then upsert is enabled."
-)
-public class AdapterMongoDb extends DBAdapterBase {
-
-	/**
-	 * The size of buffer for bulk insert. Not applicable for upsert mode.
-	 */
-	@JsonProperty
-	private int bufferSize = 10000;
-
-	/**
-	 * The upsert mode if set to <b>true</b>.
-	 */
-	@JsonProperty
-	private boolean upsert = false;
-
-	@JsonProperty
-	private String serviceBaseName;
-	/**
-	 * Custom connection to Mongo database.
-	 */
-	private MongoDbConnection connection;
-	/**
-	 * Mongo collection.
-	 */
-	private MongoCollection<Document> collection;
-	/**
-	 * DAO of DLab's resource type.
-	 */
-	private DlabResourceTypeDAO resourceTypeDAO;
-	/**
-	 * Buffer for insert operations.
-	 */
-	private List<Document> buffer;
-	/**
-	 * List of dates for delete from MongoDB.
-	 */
-	private UsageDataList usageDateList;
-
-	public String getServiceBaseName() {
-		return serviceBaseName;
-	}
-
-	public void setServiceBaseName(String serviceBaseName) {
-		this.serviceBaseName = serviceBaseName;
-	}
-
-	/**
-	 * Return the size of buffer for bulk insert.
-	 */
-	public int getBufferSize() {
-		return bufferSize;
-	}
-
-	/**
-	 * Set the size of buffer for bulk insert.
-	 *
-	 * @throws InitializationException
-	 */
-	public void setBufferSize(int bufferSize) throws InitializationException {
-		if (upsert && bufferSize <= 0) {
-			throw new InitializationException("The bufferSize must be greater than zero when upsert mode is switched" +
-					" " +
-					"on");
-		}
-		this.bufferSize = bufferSize;
-	}
-
-	/**
-	 * Return the <b>true</b> if upsert mode switched on.
-	 */
-	public boolean isUpsert() {
-		return upsert;
-	}
-
-	/**
-	 * Set the upsert mode.
-	 *
-	 * @throws InitializationException
-	 */
-	public void setUpsert(boolean upsert) throws InitializationException {
-		if (upsert && bufferSize <= 0) {
-			throw new InitializationException("Upsert mode cannot be enabled if the bufferSize is zero or less than " +
-					"zero");
-		}
-		this.upsert = upsert;
-	}
-
-	@Override
-	public void open() throws AdapterException {
-		if (connection == null) {
-			if (getMode() != Mode.WRITE) {
-				throw new AdapterException("Mode of " + getType() + " adapter may be " + Mode.WRITE + " only.");
-			}
-			connection = new MongoDbConnection(getHost(), getPort(), getDatabase(), getUsername(), getPassword());
-			setServiceBaseName();
-			collection = connection.getCollection(MongoConstants.COLLECTION_BILLING);
-			try {
-				resourceTypeDAO = new DlabResourceTypeDAO(connection);
-			} catch (InitializationException e) {
-				throw new AdapterException("Cannot initialize billing transformer to DLab format. " + e.getLocalizedMessage(), e);
-			}
-
-			connection.createBillingIndexes();
-			usageDateList = new UsageDataList();
-			buffer = (upsert || bufferSize > 0 ? new ArrayList<>(bufferSize) : null);
-		} else {
-			throw new AdapterException("Connection is already opened");
-		}
-	}
-
-	private void setServiceBaseName() {
-		connection.getCollection(COLLECTION_SETTINGS)
-				.updateOne(eq("_id", FIELD_SERIVICE_BASE_NAME), new Document("$set", new Document("value", serviceBaseName)),
-						new UpdateOptions().upsert(true));
-	}
-
-	@Override
-	public void close() throws AdapterException {
-		if (connection != null) {
-			if (upsert) {
-				connection.upsertRows(collection, buffer, usageDateList);
-			} else if (bufferSize > 0) {
-				connection.insertRows(collection, buffer);
-			}
-			buffer = null;
-			updateTotal();
-
-			try {
-				connection.close();
-			} catch (Exception e) {
-				throw new AdapterException("Cannot close connection to database " +
-						getDatabase() + ". " + e.getLocalizedMessage(), e);
-			} finally {
-				connection = null;
-			}
-		}
-	}
-
-	@Override
-	public String getEntryName() {
-		return MongoConstants.COLLECTION_BILLING;
-	}
-
-	@Override
-	public String readLine() throws AdapterException {
-		throw new AdapterException("Unimplemented method called.");
-	}
-
-	@Override
-	public void writeHeader(List<String> header) {
-		// Nothing to do
-	}
-
-	@Override
-	public Document writeRow(ReportLine row) throws AdapterException {
-		Document document;
-		try {
-			document = resourceTypeDAO.transform(row);
-		} catch (ParseException e) {
-			throw new AdapterException("Cannot transform report line. " + e.getLocalizedMessage(), e);
-		}
-
-		return document;
-	}
-
-	/**
-	 * Update total cost of resources.
-	 */
-	private void updateTotal() throws AdapterException {
-		TreeSet<String> months = new TreeSet<>();
-		try {
-			for (String date : usageDateList) {
-				months.add(date.substring(0, 7));
-			}
-			for (String month : months) {
-				resourceTypeDAO.updateMonthTotalCost(month);
-			}
-		} catch (Exception e) {
-			throw new AdapterException("Cannot update total monthly cost. " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("bufferSize", bufferSize)
-				.add("upsert", upsert);
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/mongo/DlabResourceTypeDAO.java b/services/billing-aws/src/main/java/com/epam/dlab/mongo/DlabResourceTypeDAO.java
deleted file mode 100644
index 0c95605..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/mongo/DlabResourceTypeDAO.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * 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.mongo;
-
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.exceptions.ParseException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.mongodb.client.AggregateIterable;
-import com.mongodb.client.MongoCollection;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import static com.mongodb.client.model.Accumulators.sum;
-import static com.mongodb.client.model.Aggregates.group;
-import static com.mongodb.client.model.Aggregates.match;
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.gte;
-import static com.mongodb.client.model.Filters.lte;
-import static org.apache.commons.lang3.StringUtils.EMPTY;
-
-/**
- * Provides Mongo DAO for billing resources in DLab.
- */
-public class DlabResourceTypeDAO implements MongoConstants {
-	private static final Logger LOGGER = LoggerFactory.getLogger(DlabResourceTypeDAO.class);
-
-	/**
-	 * Mongo database connection.
-	 */
-	private final MongoDbConnection connection;
-
-	/**
-	 * Service base name.
-	 */
-	private String serviceBaseName;
-	private String serviceBaseNameId;
-
-	/**
-	 * Instantiate DAO for billing resources.
-	 *
-	 * @param connection the connection to Mongo DB.
-	 * @throws InitializationException
-	 */
-	public DlabResourceTypeDAO(MongoDbConnection connection) throws InitializationException {
-		this.connection = connection;
-		setServiceBaseName();
-	}
-
-	/**
-	 * Returns the base name of service.
-	 */
-	public String getServiceBaseName() {
-		return serviceBaseName;
-	}
-
-	/**
-	 * Set the base name of service.
-	 *
-	 * @throws InitializationException
-	 */
-	private void setServiceBaseName() throws InitializationException {
-		Document d = connection.getCollection(COLLECTION_SETTINGS)
-				.find(eq(FIELD_ID, FIELD_SERIVICE_BASE_NAME))
-				.first();
-		if (d == null) {
-			throw new InitializationException("Service base name property " + COLLECTION_SETTINGS +
-					"." + FIELD_SERIVICE_BASE_NAME + " in Mongo DB not found");
-		}
-		String value = d.getOrDefault("value", EMPTY).toString();
-		if (d.isEmpty()) {
-			throw new InitializationException("Service base name property " + COLLECTION_SETTINGS +
-					"." + FIELD_SERIVICE_BASE_NAME + " in Mongo DB is empty");
-		}
-		serviceBaseName = value;
-		serviceBaseNameId = value + ":";
-		LOGGER.debug("serviceBaseName is {}", serviceBaseName);
-	}
-
-	/**
-	 * Convert and return the report line of billing to Mongo document.
-	 *
-	 * @param row report line.
-	 * @return Mongo document.
-	 * @throws ParseException
-	 */
-	public Document transform(ReportLine row) throws ParseException {
-		String resourceId = row.getDlabId();
-		if (resourceId == null || !resourceId.startsWith(serviceBaseNameId)) {
-			throw new ParseException("DlabId is not match: expected start with " + serviceBaseNameId + ", actual " +
-					resourceId);
-		}
-		resourceId = resourceId.substring(serviceBaseNameId.length());
-		Document d = new Document(ReportLine.FIELD_DLAB_ID, resourceId);
-		return d.append(ReportLine.FIELD_USAGE_DATE, row.getUsageDate())
-				.append(ReportLine.FIELD_PRODUCT, row.getProduct())
-				.append(ReportLine.FIELD_USAGE_TYPE, row.getUsageType())
-				.append(ReportLine.FIELD_USAGE, row.getUsage())
-				.append(ReportLine.FIELD_COST, row.getCost())
-				.append(ReportLine.FIELD_CURRENCY_CODE, row.getCurrencyCode())
-				.append(ReportLine.FIELD_RESOURCE_TYPE, row.getResourceType().category())
-				.append(ReportLine.FIELD_RESOURCE_ID, row.getResourceId())
-				.append(ReportLine.FIELD_TAGS, row.getTags());
-	}
-
-
-	/**
-	 * Return field condition for groupping.
-	 *
-	 * @param fieldNames the list of field names.
-	 */
-	private Document getGroupingFields(String... fieldNames) {
-		Document d = new Document();
-		for (String name : fieldNames) {
-			d.put(name, "$" + name);
-		}
-		return d;
-	}
-
-	/**
-	 * Update monthly total in Mongo DB.
-	 *
-	 * @param month the month in format YYYY-MM.
-	 * @throws InitializationException
-	 */
-	public void updateMonthTotalCost(String month) throws InitializationException {
-		LOGGER.debug("Update total cost for month {}", month);
-		try {
-			//Check month
-			SimpleDateFormat fd = new SimpleDateFormat("yyyy-MM");
-			fd.parse(month);
-		} catch (java.text.ParseException e) {
-			throw new InitializationException("Invalid month value. " + e.getLocalizedMessage(), e);
-		}
-
-		List<? extends Bson> pipeline = Arrays.asList(
-				match(and(gte(ReportLine.FIELD_USAGE_DATE, month + "-01"),
-						lte(ReportLine.FIELD_USAGE_DATE, month + "-31"))),
-				group(getGroupingFields(FIELD_DLAB_RESOURCE_ID,
-						FIELD_DLAB_RESOURCE_TYPE,
-						FIELD_USER,
-						FIELD_EXPLORATORY_NAME,
-						ReportLine.FIELD_CURRENCY_CODE,
-						ReportLine.FIELD_RESOURCE_TYPE),
-						sum(ReportLine.FIELD_COST, "$" + ReportLine.FIELD_COST))
-		);
-		AggregateIterable<Document> docs = connection.getCollection(COLLECTION_BILLING).aggregate(pipeline);
-
-		MongoCollection<Document> collection = connection.getCollection(COLLECTION_BILLING_TOTAL);
-		long deletedCount = collection.deleteMany(eq(ReportLine.FIELD_USAGE_DATE, month)).getDeletedCount();
-		LOGGER.debug("{} documents has been deleted from collection {}", deletedCount, COLLECTION_BILLING_TOTAL);
-		List<Document> totals = new ArrayList<>();
-		for (Document d : docs) {
-			Document total = (Document) d.get(FIELD_ID);
-			total
-					.append(ReportLine.FIELD_USAGE_DATE, month)
-					.append(ReportLine.FIELD_COST, d.getDouble(ReportLine.FIELD_COST));
-			totals.add(total);
-		}
-		if (!totals.isEmpty()) {
-			LOGGER.debug("{} documents will be inserted into collection {}", totals.size(), COLLECTION_BILLING_TOTAL);
-			collection.insertMany(totals);
-		}
-	}
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/mongo/MongoConstants.java b/services/billing-aws/src/main/java/com/epam/dlab/mongo/MongoConstants.java
deleted file mode 100644
index 68c56cd..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/mongo/MongoConstants.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.mongo;
-
-/** The constants names of collections and fields in Mongo DB.
- */
-public interface MongoConstants {
-	/** Name of ID field. */
-	String FIELD_ID = "_id";
-    
-	/** Collection environment settings. */
-    String COLLECTION_SETTINGS = "settings";
-    String FIELD_SERIVICE_BASE_NAME = "conf_service_base_name";
-
-    /** Collection user AWS credentials. */
-    String COLLECTION_USER_EDGE = "userCloudCredentials";
-
-    /** Collection user instances. */
-    String COLLECTION_USER_INSTANCES = "userInstances";
-    String FIELD_EXPLORATORY_NAME = "exploratory_name";
-    String FIELD_USER = "user";
-	String FIELD_IMAGE = "image";
-    String FIELD_EXPLORATORY_ID = "exploratory_id";
-    String FIELD_CURRENCY_CODE = "currency_code";
-    String FIELD_COMPUTATIONAL_RESOURCES = "computational_resources";
-    String FIELD_COMPUTATIONAL_ID = "computational_id";
-    String FIELD_COMPUTATIONAL_NAME = "computational_name";
-	String FIELD_DATAENGINE_INSTANCE_COUNT = "dataengine_instance_count";
-
-    /** Collection billing. */
-    String COLLECTION_BILLING = "billing";
-	String FIELD_DLAB_RESOURCE_ID = "dlab_resource_id";
-	String FIELD_RESOURCE_NAME = "resource_name";
-	String FIELD_PROJECT = "project";
-	String FIELD_DLAB_RESOURCE_TYPE = "dlab_resource_type";
-
-    /** Collection billingTotal. */
-	String COLLECTION_BILLING_TOTAL = "billingTotal";
-	String FIELD_USAGE_DATE_START = "from";
-	String FIELD_USAGE_DATE_END = "to";
-	String BILLING_DATA_COLLECTION = "BillingData";
-}
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/mongo/MongoDbConnection.java b/services/billing-aws/src/main/java/com/epam/dlab/mongo/MongoDbConnection.java
deleted file mode 100644
index 6e24498..0000000
--- a/services/billing-aws/src/main/java/com/epam/dlab/mongo/MongoDbConnection.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * 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.mongo;
-
-import com.epam.dlab.core.aggregate.UsageDataList;
-import com.epam.dlab.exceptions.AdapterException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.mongodb.BasicDBObject;
-import com.mongodb.MongoClient;
-import com.mongodb.MongoCredential;
-import com.mongodb.ServerAddress;
-import com.mongodb.WriteConcern;
-import com.mongodb.client.MongoCollection;
-import com.mongodb.client.MongoDatabase;
-import com.mongodb.client.model.IndexOptions;
-import com.mongodb.client.result.DeleteResult;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-
-import static com.mongodb.client.model.Filters.eq;
-
-/**
- * Provides operation with Mongo database and billing report.
- */
-public class MongoDbConnection implements Closeable {
-	private static final Logger LOGGER = LoggerFactory.getLogger(MongoDbConnection.class);
-
-	/**
-	 * Mongo client.
-	 */
-	private MongoClient client;
-
-	/**
-	 * Mongo database.
-	 */
-	private MongoDatabase database;
-
-
-	/**
-	 * Instantiate the helper for Mongo database adapter.
-	 *
-	 * @param host         the host name.
-	 * @param port         the port.
-	 * @param databaseName the name of database.
-	 * @param username     the name of user.
-	 * @param password     the password.
-	 * @throws AdapterException
-	 */
-	public MongoDbConnection(String host, int port, String databaseName, String username, String password) throws
-			AdapterException {
-		try {
-			client = new MongoClient(
-					new ServerAddress(host, port),
-					Collections.singletonList(
-							MongoCredential.createCredential(username, databaseName, password.toCharArray())));
-			database = client.getDatabase(databaseName).withWriteConcern(WriteConcern.ACKNOWLEDGED);
-		} catch (Exception e) {
-			throw new AdapterException("Cannot create connection to database " +
-					databaseName + ". " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Close connection to Mongo database.
-	 */
-	@Override
-	public void close() throws IOException {
-		if (client != null) {
-			try {
-				client.close();
-			} catch (Exception e) {
-				throw new IOException(e.getLocalizedMessage(), e);
-			} finally {
-				client = null;
-				database = null;
-			}
-		}
-	}
-
-	/**
-	 * Create index on billing collection.
-	 *
-	 * @param indexName the name of index.
-	 * @param index     the index options.
-	 */
-	private void createBillingIndexes(String indexName, Bson index) {
-		MongoCollection<Document> collection = database.getCollection(MongoConstants.COLLECTION_BILLING);
-		IndexOptions options = new IndexOptions().name(MongoConstants.COLLECTION_BILLING + indexName);
-		try {
-			collection
-					.createIndex(index, options);
-		} catch (Exception e) {
-			LOGGER.warn("Cannot create index {} on collection {}. {}", options.getName(),
-					MongoConstants.COLLECTION_BILLING, e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Create index on Mongo collection for fast upsert operations.
-	 */
-	public void createBillingIndexes() {
-		createBillingIndexes("_IntervalIdx",
-				new BasicDBObject()
-						.append(ReportLine.FIELD_USER_ID, 1)
-						.append(ReportLine.FIELD_USAGE_DATE, 2));
-		createBillingIndexes("_ExploratoryIdx",
-				new BasicDBObject()
-						.append(ReportLine.FIELD_USER_ID, 1)
-						.append(MongoConstants.FIELD_EXPLORATORY_NAME, 2));
-	}
-
-	/**
-	 * Return the collection of Mongo database.
-	 *
-	 * @param collectionName the name of collection.
-	 */
-	public MongoCollection<Document> getCollection(String collectionName) {
-		return database.getCollection(collectionName);
-	}
-
-	/**
-	 * Insert document to Mongo.
-	 *
-	 * @param collection the name of collection.
-	 * @param document   the document.
-	 * @throws AdapterException
-	 */
-	public void insertOne(MongoCollection<Document> collection, Document document) throws AdapterException {
-		try {
-			collection.insertOne(document);
-		} catch (Exception e) {
-			throw new AdapterException("Cannot insert document into collection " +
-					collection.getNamespace() + ": " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Insert documents from list to Mongo collection and clear list.
-	 *
-	 * @param collection Mongo collection.
-	 * @param documents  the list of documents.
-	 * @throws AdapterException
-	 */
-	public void insertRows(MongoCollection<Document> collection, List<Document> documents) throws AdapterException {
-		try {
-			if (!documents.isEmpty()) {
-				collection.insertMany(documents);
-				LOGGER.debug("{} documents has been inserted into collection {}",
-						documents.size(), collection.getNamespace());
-				documents.clear();
-			}
-		} catch (Exception e) {
-			throw new AdapterException("Cannot insert new documents into collection " +
-					collection.getNamespace() + ": " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Insert documents from list to Mongo collection and clear list.
-	 *
-	 * @param collection    Mongo collection.
-	 * @param documents     the list of documents.
-	 * @param usageDateList list of the data interval to deletion old data from Mongo.
-	 * @throws AdapterException
-	 */
-	public void upsertRows(MongoCollection<Document> collection, List<Document> documents, UsageDataList usageDateList)
-			throws AdapterException {
-		deleteRows(collection, usageDateList);
-		insertRows(collection, documents);
-	}
-
-	/**
-	 * Delete the documents from Mongo collection.
-	 *
-	 * @param collection    Mongo collection.
-	 * @param usageDateList list of the data interval to deletion data from Mongo.
-	 * @throws AdapterException
-	 */
-	public void deleteRows(MongoCollection<Document> collection, UsageDataList usageDateList)
-			throws AdapterException {
-		try {
-			long rowCount = 0;
-			for (String date : usageDateList) {
-				if (!usageDateList.get(date)) {
-					DeleteResult result = collection.deleteMany(eq(ReportLine.FIELD_USAGE_DATE, date));
-					rowCount += result.getDeletedCount();
-					usageDateList.set(date, true);
-				}
-			}
-			if (rowCount > 0) {
-				LOGGER.debug("{} documents has been deleted from collection {}",
-						rowCount, collection.getNamespace());
-			}
-		} catch (Exception e) {
-			throw new AdapterException("Cannot delete old rows from collection " +
-					collection.getNamespace() + ": " + e.getLocalizedMessage(), e);
-		}
-	}
-}
diff --git a/services/billing-aws/src/main/resources/application.yml b/services/billing-aws/src/main/resources/application.yml
index 8b1b641..7849fb7 100644
--- a/services/billing-aws/src/main/resources/application.yml
+++ b/services/billing-aws/src/main/resources/application.yml
@@ -26,7 +26,7 @@
     mongodb:
       username: admin
       password: MONGO_PASSWORD
-      database: dlabdb
+      database: datalabdb
       port: 27017
       host: MONGO_HOST
 
@@ -41,14 +41,14 @@
 server.ssl.key-alias: ssn
 
 logging:
-  file: /var/opt/dlab/log/ssn/billing.log
+  file: /var/opt/datalab/log/ssn/billing.log
   level:
     com:
       epam: trace
 
 keycloak:
   bearer-only: true
-  realm: dlab
+  realm: datalab
   resource: KEYCLOAK_CLIENT_ID
   credentials.secret: KEYCLOAK_CLIENT_SECRET
   ssl-required: none
diff --git a/services/billing-aws/src/main/resources/com.epam.datalab.configuration.BillingToolConfigurationFactory b/services/billing-aws/src/main/resources/com.epam.datalab.configuration.BillingToolConfigurationFactory
new file mode 100644
index 0000000..6616dfb
--- /dev/null
+++ b/services/billing-aws/src/main/resources/com.epam.datalab.configuration.BillingToolConfigurationFactory
@@ -0,0 +1,8 @@
+com.epam.datalab.logging.AppenderConsole
+com.epam.datalab.logging.AppenderFile
+com.epam.datalab.module.AdapterConsole
+com.epam.datalab.module.AdapterFile
+com.epam.datalab.module.aws.AdapterS3File
+com.epam.datalab.mongo.AdapterMongoDb
+com.epam.datalab.module.ParserCsv
+com.epam.datalab.module.aws.FilterAWS
\ No newline at end of file
diff --git a/services/billing-aws/src/main/resources/com.epam.dlab.Help.conf.txt b/services/billing-aws/src/main/resources/com.epam.dlab.Help.conf.txt
index 44e7071..7a66397 100644
--- a/services/billing-aws/src/main/resources/com.epam.dlab.Help.conf.txt
+++ b/services/billing-aws/src/main/resources/com.epam.dlab.Help.conf.txt
@@ -1,7 +1,7 @@
 Configuration syntax:
 
 # Working file for store billing report variables.
-workingFile: /opt/dlab/tmp/result/billing-data.json
+workingFile: /opt/datalab/tmp/result/billing-data.json
 
 scheduler:
 # Schedule is comma separated values of time in format hh[:mm[:ss]]. hh - in the 24-hour clock, at 8:15PM is 20:15.
diff --git a/services/billing-aws/src/main/resources/com.epam.dlab.configuration.BillingToolConfigurationFactory b/services/billing-aws/src/main/resources/com.epam.dlab.configuration.BillingToolConfigurationFactory
deleted file mode 100644
index ee6ea90..0000000
--- a/services/billing-aws/src/main/resources/com.epam.dlab.configuration.BillingToolConfigurationFactory
+++ /dev/null
@@ -1,8 +0,0 @@
-com.epam.dlab.logging.AppenderConsole
-com.epam.dlab.logging.AppenderFile
-com.epam.dlab.module.AdapterConsole
-com.epam.dlab.module.AdapterFile
-com.epam.dlab.module.aws.AdapterS3File
-com.epam.dlab.mongo.AdapterMongoDb
-com.epam.dlab.module.ParserCsv
-com.epam.dlab.module.aws.FilterAWS
\ No newline at end of file
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/configuration/BillingToolConfigurationTest.java b/services/billing-aws/src/test/java/com/epam/datalab/configuration/BillingToolConfigurationTest.java
new file mode 100644
index 0000000..4e86c29
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/configuration/BillingToolConfigurationTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.datalab.configuration;
+
+import com.epam.datalab.core.AdapterBase.Mode;
+import com.epam.datalab.core.aggregate.AggregateGranularity;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.module.AdapterConsole;
+import com.epam.datalab.module.AdapterFile;
+import com.epam.datalab.module.ModuleName;
+import com.epam.datalab.module.ParserCsv;
+import com.epam.datalab.module.aws.FilterAWS;
+import com.fasterxml.jackson.databind.JsonNode;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+
+public class BillingToolConfigurationTest {
+
+	@Test
+	@Ignore
+	public void config() throws InitializationException {
+		JsonNode node = new ConfigJsonGenerator()
+				.withAdapterIn("type", ModuleName.ADAPTER_FILE,
+						"file", "fileIn.csv")
+				.withAdapterOut("type", ModuleName.ADAPTER_CONSOLE)
+				.withFilter("type", ModuleName.FILTER_AWS,
+						"currencyCode", "USD",
+						"columnDatalabTag", "user:user:tag",
+						"serviceBaseName", "sbn")
+				.withParser("type", ModuleName.PARSER_CSV,
+						"columnMapping", "datalab_id=user:user:tag;usage_date=UsageStartDate;product=ProductName;" +
+								"tags=Operation,ItemDescription",
+						"whereCondition", "UsageStartDate >= '2017-04-12'",
+						"aggregate", "day",
+						"headerLineNo", "5",
+						"skipLines", "10",
+						"fieldSeparator", ";",
+						"fieldTerminator", "^",
+						"escapeChar", "/",
+						"decimalSeparator", ",",
+						"groupingSeparator", "_")
+				.build();
+		BillingToolConfiguration conf = BillingToolConfigurationFactory.build(node, BillingToolConfiguration.class);
+		ParserCsv parser = (ParserCsv) conf.build();
+
+		assertNotNull("Parser was not build", parser);
+
+		AdapterFile in = (AdapterFile) parser.getAdapterIn();
+		assertEquals(ModuleName.ADAPTER_FILE, in.getType());
+		assertEquals(Mode.READ, in.getMode());
+		assertEquals("fileIn.csv", in.getFile());
+
+		AdapterConsole out = (AdapterConsole) parser.getAdapterOut();
+		assertEquals(ModuleName.ADAPTER_CONSOLE, out.getType());
+		assertEquals(Mode.WRITE, out.getMode());
+
+		FilterAWS filter = (FilterAWS) parser.getFilter();
+		assertEquals(ModuleName.FILTER_AWS, filter.getType());
+		assertEquals("USD", filter.getCurrencyCode());
+		assertEquals("user:user:tag", filter.getColumnDatalabTag());
+		assertEquals("sbn", filter.getServiceBaseName());
+		assertEquals(parser, filter.getParser());
+
+		assertEquals(ModuleName.PARSER_CSV, parser.getType());
+		assertEquals("datalab_id=user:user:tag;usage_date=UsageStartDate;product=ProductName;tags=Operation,ItemDescription",
+				parser.getColumnMapping());
+		assertEquals("UsageStartDate >= '2017-04-12'", parser.getWhereCondition());
+		assertEquals(AggregateGranularity.DAY, parser.getAggregate());
+		assertEquals(5, parser.getHeaderLineNo());
+		assertEquals(10, parser.getSkipLines());
+		assertEquals(';', parser.getFieldSeparator());
+		assertEquals('^', parser.getFieldTerminator());
+		assertEquals('/', parser.getEscapeChar());
+		assertEquals(',', parser.getDecimalSeparator());
+		assertEquals('_', parser.getGroupingSeparator());
+	}
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/configuration/ConfigJsonGeneratorTest.java b/services/billing-aws/src/test/java/com/epam/datalab/configuration/ConfigJsonGeneratorTest.java
new file mode 100644
index 0000000..b967bde
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/configuration/ConfigJsonGeneratorTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.datalab.configuration;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+
+public class ConfigJsonGeneratorTest {
+
+	private void checkProperty(JsonNode conf, String module, String name, String expectedValue) {
+		JsonNode m = conf.get(module);
+		assertNotNull("Module \"" + module + "\" not found in JSON configuration", m);
+
+		JsonNode item = m.get(0);
+		assertNotNull("Property \"" + module + "." + name + "\" not found in JSON configuration", item);
+
+		JsonNode p = item.get(name);
+		assertNotNull("Property \"" + module + "." + name + "\" not found in JSON configuration", p);
+
+		assertEquals(expectedValue, p.asText());
+	}
+
+	@Test
+	public void build() throws IOException {
+		JsonNode conf = new ConfigJsonGenerator()
+				.withAdapterIn("adapterInProperty", "adapterInValue")
+				.withAdapterOut("adapterOutProperty", "adapterOutValue")
+				.withParser("parserProperty", "parserValue")
+				.withFilter("filterProperty", "filterValue")
+				.build();
+
+		checkProperty(conf, "adapterIn", "adapterInProperty", "adapterInValue");
+		checkProperty(conf, "adapterOut", "adapterOutProperty", "adapterOutValue");
+		checkProperty(conf, "parser", "parserProperty", "parserValue");
+		checkProperty(conf, "filter", "filterProperty", "filterValue");
+	}
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/configuration/ConfigurationValidatorTest.java b/services/billing-aws/src/test/java/com/epam/datalab/configuration/ConfigurationValidatorTest.java
new file mode 100644
index 0000000..429e4a1
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/configuration/ConfigurationValidatorTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.datalab.configuration;
+
+import com.epam.datalab.exceptions.InitializationException;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.junit.Test;
+
+import javax.validation.constraints.NotNull;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.fail;
+
+public class ConfigurationValidatorTest {
+
+    class TestProperty {
+
+        @JsonProperty
+        @NotNull
+        String property;
+    }
+
+    @Test
+    public void validate() throws InitializationException {
+        ConfigurationValidator<TestProperty> v = new ConfigurationValidator<>();
+        TestProperty o = new TestProperty();
+        try {
+            v.validate(o);
+            fail("Property is null but validate is passed");
+        } catch (InitializationException e) {
+            // OK
+        }
+        o.property = "value";
+        v.validate(o);
+        assertEquals("value", o.property);
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/configuration/LoggingConfigurationFactoryTest.java b/services/billing-aws/src/test/java/com/epam/datalab/configuration/LoggingConfigurationFactoryTest.java
new file mode 100644
index 0000000..b929eb3
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/configuration/LoggingConfigurationFactoryTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.datalab.configuration;
+
+import ch.qos.logback.classic.Level;
+import com.epam.datalab.core.BillingUtils;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.logging.AppenderBase;
+import com.epam.datalab.logging.AppenderConsole;
+import com.epam.datalab.logging.AppenderFile;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.guava.GuavaModule;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+
+public class LoggingConfigurationFactoryTest {
+
+    private ObjectMapper getMapper() throws InitializationException {
+        ObjectMapper mapper = new ObjectMapper().enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+        mapper.registerModule(new GuavaModule());
+        for (Class<?> clazz : BillingUtils.getModuleClassList()) {
+            mapper.registerSubtypes(clazz);
+        }
+        return mapper;
+    }
+
+    @Test
+    public void config() throws IOException, InitializationException {
+        // {"filter":[{"filterProperty":"filterValue"}],"parser":[{"parserProperty":"parserValue"}],"adapterIn":[{"adapterInProperty":"adapterInValue"}],"adapterOut":[{"adapterOutProperty":"adapterOutValue"}]}
+        final String jsonString =
+                "{\n" +
+                        "  \"level\":\"INFO\",\n" +
+                        "  \"loggers\":{\n" +
+                        "    \"com.epam\":\"DEBUG\",\n" +
+                        "    \"org.apache.http\":\"WARN\"},\n" +
+                        "  \"appenders\":[\n" +
+                        "    {\"type\":\"console\"},\n" +
+                        "    {\"type\":\"file\",\n" +
+                        "      \"currentLogFilename\":\"billing.log\",\n" +
+                        "      \"archive\":true,\n" +
+                        "      \"archivedLogFilenamePattern\":\"billing-%d{yyyy-MM-dd}.log.gz\",\n" +
+                        "      \"archivedFileCount\":10}]\n" +
+                        "}";
+
+        ObjectMapper mapper = getMapper();
+        JsonNode conf = mapper.readTree(jsonString); // validate JSON
+        LoggingConfigurationFactory logger = mapper.readValue(conf.toString(), LoggingConfigurationFactory.class);
+
+        assertEquals(Level.INFO, logger.getLevel());
+        assertEquals(Level.DEBUG, logger.getLoggers().get("com.epam"));
+        assertEquals(Level.WARN, logger.getLoggers().get("org.apache.http"));
+
+        List<AppenderBase> appenders = logger.getAppenders();
+        assertEquals("Invalid number of appenders", 2, appenders.size());
+
+        AppenderConsole ac = (AppenderConsole) appenders.get(0);
+        assertNotNull(ac);
+
+        AppenderFile af = (AppenderFile) appenders.get(1);
+        assertEquals("billing.log", af.getCurrentLogFilename());
+        assertEquals(true, af.getArchive());
+        assertEquals("billing-%d{yyyy-MM-dd}.log.gz", af.getArchivedLogFilenamePattern());
+        assertEquals(10, af.getArchivedFileCount());
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/core/BillingUtilsTest.java b/services/billing-aws/src/test/java/com/epam/datalab/core/BillingUtilsTest.java
new file mode 100644
index 0000000..b73b7ce
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/core/BillingUtilsTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.datalab.core;
+
+import com.epam.datalab.core.parser.ParserBase;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.logging.AppenderBase;
+import com.epam.datalab.logging.AppenderConsole;
+import com.epam.datalab.logging.AppenderFile;
+import com.epam.datalab.module.AdapterConsole;
+import com.epam.datalab.module.AdapterFile;
+import com.epam.datalab.module.ParserCsv;
+import com.epam.datalab.module.aws.AdapterS3File;
+import com.epam.datalab.module.aws.FilterAWS;
+import com.epam.datalab.mongo.AdapterMongoDb;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.fail;
+
+public class BillingUtilsTest {
+
+    @Test
+    public void stringsToMap() {
+        Map<String, String> map = BillingUtils.stringsToMap(
+                "key1", "value1",
+                "key2", "value2");
+        assertEquals(2, map.size());
+        assertEquals("value1", map.get("key1"));
+        assertEquals("value2", map.get("key2"));
+
+        try {
+            map = BillingUtils.stringsToMap(
+                    "key1", "value1",
+                    "key2");
+            fail("Missed value2 is passed");
+        } catch (IllegalArgumentException e) {
+            // OK
+        }
+    }
+
+    private void checkModule(List<Class<?>> list, Class<?> moduleClass) {
+        for (Class<?> module : list) {
+            if (module == moduleClass) {
+                return;
+            }
+        }
+        fail("Module " + moduleClass.getName() + " is not in module list");
+    }
+
+    @Test
+    public void getModuleClassList() throws InitializationException {
+        List<Class<?>> list = BillingUtils.getModuleClassList();
+        checkModule(list, AdapterConsole.class);
+        checkModule(list, AdapterFile.class);
+        checkModule(list, AdapterS3File.class);
+        checkModule(list, AdapterMongoDb.class);
+        checkModule(list, FilterAWS.class);
+        checkModule(list, ParserCsv.class);
+        checkModule(list, AppenderConsole.class);
+        checkModule(list, AppenderFile.class);
+    }
+
+    @Test
+    public void classChildOf() {
+        assertEquals(true, BillingUtils.classChildOf(AdapterConsole.class, AdapterBase.class));
+        assertEquals(false, BillingUtils.classChildOf(AdapterConsole.class, FilterBase.class));
+        assertEquals(true, BillingUtils.classChildOf(FilterAWS.class, FilterBase.class));
+        assertEquals(false, BillingUtils.classChildOf(FilterAWS.class, ParserBase.class));
+        assertEquals(true, BillingUtils.classChildOf(ParserCsv.class, ParserBase.class));
+        assertEquals(false, BillingUtils.classChildOf(ParserCsv.class, AppenderBase.class));
+        assertEquals(true, BillingUtils.classChildOf(AppenderConsole.class, AppenderBase.class));
+        assertEquals(false, BillingUtils.classChildOf(AppenderConsole.class, AdapterBase.class));
+    }
+
+    @Test
+    public void getModuleType() {
+        assertEquals(ModuleType.ADAPTER, BillingUtils.getModuleType(AdapterConsole.class));
+        assertEquals(ModuleType.ADAPTER, BillingUtils.getModuleType(AdapterFile.class));
+        assertEquals(ModuleType.ADAPTER, BillingUtils.getModuleType(AdapterS3File.class));
+        assertEquals(ModuleType.ADAPTER, BillingUtils.getModuleType(AdapterMongoDb.class));
+        assertEquals(ModuleType.FILTER, BillingUtils.getModuleType(FilterAWS.class));
+        assertEquals(ModuleType.PARSER, BillingUtils.getModuleType(ParserCsv.class));
+        assertEquals(ModuleType.LOGAPPENDER, BillingUtils.getModuleType(AppenderConsole.class));
+        assertEquals(ModuleType.LOGAPPENDER, BillingUtils.getModuleType(AppenderFile.class));
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/core/aggregate/DataAggregatorTest.java b/services/billing-aws/src/test/java/com/epam/datalab/core/aggregate/DataAggregatorTest.java
new file mode 100644
index 0000000..d14bc9f
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/core/aggregate/DataAggregatorTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.datalab.core.aggregate;
+
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class DataAggregatorTest {
+
+    @Test
+    public void append() {
+        UsageDataList list = new UsageDataList();
+
+        list.append("2017-04-12");
+        list.append("2017-04-12");
+        list.append("2017-04-14");
+
+        assertEquals(2, list.size());
+
+        assertEquals(Boolean.FALSE, list.get("2017-04-12"));
+        assertEquals(Boolean.FALSE, list.get("2017-04-14"));
+
+        list.set("2017-04-14", true);
+        assertEquals(Boolean.TRUE, list.get("2017-04-14"));
+
+        list.clear();
+        assertEquals(0, list.size());
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/core/aggregate/UsageDataListTest.java b/services/billing-aws/src/test/java/com/epam/datalab/core/aggregate/UsageDataListTest.java
new file mode 100644
index 0000000..201d1f4
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/core/aggregate/UsageDataListTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.datalab.core.aggregate;
+
+import com.epam.datalab.model.aws.ReportLine;
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.fail;
+
+public class UsageDataListTest {
+
+    @Test
+    public void day() {
+        DataAggregator agg = new DataAggregator(AggregateGranularity.DAY);
+        ReportLine r;
+
+        r = new ReportLine();
+        r.setUsageDate("2017-04-12 12:34:56");
+        r.setCost(1.2);
+        r.setUsage(10.1);
+        agg.append(r);
+
+        r = new ReportLine();
+        r.setUsageDate("2017-04-12 12:34:78");
+        r.setCost(3.4);
+        r.setUsage(20.2);
+        agg.append(r);
+
+        r = new ReportLine();
+        r.setUsageDate("2017-04-14 11:22:33");
+        r.setCost(5.6);
+        r.setUsage(40.4);
+        agg.append(r);
+
+        assertEquals(AggregateGranularity.DAY, agg.getGranularity());
+        assertEquals(2, agg.size());
+
+        assertEquals("2017-04-12", agg.get(0).getUsageDate());
+        assertEquals(4.6, agg.get(0).getCost());
+        assertEquals(30.3, agg.get(0).getUsage(), 0.000001);
+
+        assertEquals("2017-04-14", agg.get(1).getUsageDate());
+        assertEquals(5.6, agg.get(1).getCost());
+        assertEquals(40.4, agg.get(1).getUsage());
+
+        agg.clear();
+        assertEquals(0, agg.size());
+    }
+
+    @Test
+    public void month() {
+        DataAggregator agg = new DataAggregator(AggregateGranularity.MONTH);
+        ReportLine r;
+
+        r = new ReportLine();
+        r.setUsageDate("2017-04-12 12:34:56");
+        r.setCost(1.2);
+        r.setUsage(10.1);
+        agg.append(r);
+
+        r = new ReportLine();
+        r.setUsageDate("2017-04-12 12:34:78");
+        r.setCost(3.4);
+        r.setUsage(20.2);
+        agg.append(r);
+
+        r = new ReportLine();
+        r.setUsageDate("2017-05-14 11:22:33");
+        r.setCost(5.6);
+        r.setUsage(40.4);
+        agg.append(r);
+
+        assertEquals(AggregateGranularity.MONTH, agg.getGranularity());
+        assertEquals(2, agg.size());
+
+        assertEquals("2017-04", agg.get(0).getUsageDate());
+        assertEquals(4.6, agg.get(0).getCost());
+        assertEquals(30.3, agg.get(0).getUsage(), 0.000001);
+
+        assertEquals("2017-05", agg.get(1).getUsageDate());
+        assertEquals(5.6, agg.get(1).getCost());
+        assertEquals(40.4, agg.get(1).getUsage());
+
+        agg.clear();
+        assertEquals(0, agg.size());
+    }
+
+    @Test
+    public void none() {
+        try {
+            new DataAggregator(AggregateGranularity.NONE);
+            fail("DataArggregator should not have been created");
+        } catch (IllegalArgumentException e) {
+            // OK
+        }
+    }
+
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/core/parser/BillingResourceTypeTest.java b/services/billing-aws/src/test/java/com/epam/datalab/core/parser/BillingResourceTypeTest.java
new file mode 100644
index 0000000..a84f034
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/core/parser/BillingResourceTypeTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.datalab.core.parser;
+
+import com.epam.datalab.model.aws.BillingResourceType;
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class BillingResourceTypeTest {
+
+    @Test
+    public void test() {
+        BillingResourceType type = BillingResourceType.of("cluster");
+
+        assertEquals(BillingResourceType.CLUSTER, type);
+        assertEquals(BillingResourceType.CLUSTER.toString(), "CLUSTER");
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/core/parser/ColumnInfoTest.java b/services/billing-aws/src/test/java/com/epam/datalab/core/parser/ColumnInfoTest.java
new file mode 100644
index 0000000..4b03748
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/core/parser/ColumnInfoTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab.core.parser;
+
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class ColumnInfoTest {
+
+    @Test
+    public void test() {
+        ColumnInfo ci = new ColumnInfo("target", "source", 123);
+
+        assertEquals("target", ci.targetName);
+        assertEquals("source", ci.sourceName);
+        assertEquals(123, ci.sourceIndex);
+    }
+
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/core/parser/ColumnMetaTest.java b/services/billing-aws/src/test/java/com/epam/datalab/core/parser/ColumnMetaTest.java
new file mode 100644
index 0000000..f776309
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/core/parser/ColumnMetaTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.datalab.core.parser;
+
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.model.aws.ReportLine;
+import com.google.common.collect.Lists;
+import org.junit.Test;
+
+import java.util.List;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class ColumnMetaTest {
+
+    @Test
+    public void getColumnIndexByName() throws InitializationException {
+        final List<String> columns = Lists.newArrayList("sCol1", "sCol2", "sCol3", "sCol4");
+
+        assertEquals(0, ColumnMeta.getColumnIndexByName("sCol1", columns));
+        assertEquals(1, ColumnMeta.getColumnIndexByName("sCol2", columns));
+        assertEquals(3, ColumnMeta.getColumnIndexByName("sCol4", columns));
+
+        try {
+            ColumnMeta.getColumnIndexByName("NotFound", columns);
+
+            throw new RuntimeException("Test failed");
+        } catch (InitializationException e) {
+            // OK
+        }
+    }
+
+    private void checkMapping(ColumnInfo info, String targetColumnName, String sourceColumnName, int
+            sourceColumnIndex) {
+        assertEquals(targetColumnName, info.targetName);
+        assertEquals(sourceColumnName, info.sourceName);
+        assertEquals(sourceColumnIndex, info.sourceIndex);
+    }
+
+    @Test
+    public void create() throws InitializationException {
+        final String mapping =
+                ColumnMeta.COLUMN_NAMES[0] + "=sCol2;" +
+                        ColumnMeta.COLUMN_NAMES[1] + "=$1;" +
+                        ReportLine.FIELD_TAGS + "=sCol4,$3";
+        final List<String> columns = Lists.newArrayList("sCol1", "sCol2", "sCol3", "sCol4");
+        ColumnMeta meta = new ColumnMeta(mapping, columns);
+
+        assertEquals(4, meta.getSourceColumnNames().size());
+        assertEquals("sCol1", meta.getSourceColumnNames().get(0));
+        assertEquals("sCol2", meta.getSourceColumnNames().get(1));
+        assertEquals("sCol3", meta.getSourceColumnNames().get(2));
+        assertEquals("sCol4", meta.getSourceColumnNames().get(3));
+
+        assertEquals(ColumnMeta.COLUMN_NAMES.length + 1, meta.getTargetColumnNames().size());
+        assertEquals(ColumnMeta.COLUMN_NAMES[0], meta.getTargetColumnNames().get(0));
+        assertEquals("sCol4", meta.getTargetColumnNames().get(ColumnMeta.COLUMN_NAMES.length - 1));
+        assertEquals("sCol3", meta.getTargetColumnNames().get(ColumnMeta.COLUMN_NAMES.length));
+
+        assertEquals(ColumnMeta.COLUMN_NAMES.length + 1, meta.getColumnMapping().size());
+        checkMapping(meta.getColumnMapping().get(0), ColumnMeta.COLUMN_NAMES[0], "sCol2", 1);
+        checkMapping(meta.getColumnMapping().get(1), ColumnMeta.COLUMN_NAMES[1], "sCol1", 0);
+        checkMapping(meta.getColumnMapping().get(ColumnMeta.COLUMN_NAMES.length - 1), ColumnMeta
+                .COLUMN_NAMES[ColumnMeta.COLUMN_NAMES.length - 1], "sCol4", 3);
+        checkMapping(meta.getColumnMapping().get(ColumnMeta.COLUMN_NAMES.length), ColumnMeta.COLUMN_NAMES[ColumnMeta
+                .COLUMN_NAMES.length - 1], "sCol3", 2);
+    }
+
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/core/parser/CommonFormatTest.java b/services/billing-aws/src/test/java/com/epam/datalab/core/parser/CommonFormatTest.java
new file mode 100644
index 0000000..7de4f01
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/core/parser/CommonFormatTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.datalab.core.parser;
+
+import com.epam.datalab.core.BillingUtils;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.exceptions.ParseException;
+import com.epam.datalab.model.aws.BillingResourceType;
+import com.epam.datalab.model.aws.ReportLine;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.junit.Test;
+
+import java.util.List;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class CommonFormatTest {
+
+    private CommonFormat getInstance() throws InitializationException {
+        final List<String> columns = Lists.newArrayList("sCol1", "sCol2", "sCol3", "sCol4");
+        final String mapping = ReportLine.FIELD_DATALAB_ID + "=sCol2;" +
+                ReportLine.FIELD_USER_ID + "=$1;" + ReportLine.FIELD_TAGS + "=$4,sCol3";
+        ColumnMeta meta = new ColumnMeta(mapping, columns);
+        return new CommonFormat(meta, '.', ' ');
+    }
+
+    @Test
+    public void toCommonFormat() throws InitializationException, ParseException {
+        final CommonFormat format = getInstance();
+        final List<String> values = Lists.newArrayList("value1", "value2", "value3", "value4");
+        final ReportLine r = format.toCommonFormat(values);
+
+        assertEquals("value2", r.getDatalabId());
+        assertEquals("value1", r.getUser());
+        assertEquals(2, r.getTags().size());
+        assertEquals("value4", r.getTags().get("sCol4"));
+        assertEquals("value3", r.getTags().get("sCol3"));
+
+        assertEquals(123456.789, format.parseDouble("column1", "123 456.789"));
+        assertEquals("12345.678", CommonFormat.doubleToString(12345.678));
+    }
+
+    @Test
+    public void rowToString() throws ParseException {
+        final List<String> values = Lists.newArrayList("val\"ue1", "\"val,;ue2\"", "value3", "value4");
+        String line = CommonFormat.rowToString(values);
+        assertEquals("\"val\\\"ue1\",\"\\\"val,;ue2\\\"\",\"value3\",\"value4\"", line);
+
+        final ReportLine r = new ReportLine();
+        r.setDatalabId("accountId");
+        r.setUser("user");
+        r.setUsageDate("2016-03-20");
+        r.setProduct("Amazon Elastic Compute Cloud");
+        r.setUsageType("usageType");
+        r.setUsage(56.7);
+        r.setCost(1234.56789);
+        r.setCurrencyCode("USD");
+        r.setResourceTypeId("i-1234567890abcdefg");
+        r.setTags(Maps.newLinkedHashMap(BillingUtils.stringsToMap("tag1", "value1", "tag2", "value2")));
+        line = CommonFormat.rowToString(r);
+        assertEquals("\"accountId\",\"user\",\"2016-03-20\",\"Amazon Elastic Compute Cloud\"," +
+                "\"usageType\",\"56.7\",\"1234.56789\",\"USD\"," +
+                "\"COMPUTER\",\"i-1234567890abcdefg\"," +
+                "\"value1\",\"value2\"", line);
+    }
+
+    @Test
+    public void toReportLine() throws InitializationException, ParseException {
+        final CommonFormat format = getInstance();
+        final List<String> values = Lists.newArrayList(
+                "accountId", "user", "2016-03-27",
+                "Amazon Elastic Compute Cloud", "usageType", "56.7", "1234.56789", "USD",
+                "i-1234567890abcdefg", "value1", "value2");
+        final ReportLine r = format.toReportLine(values);
+
+        assertEquals("accountId", r.getDatalabId());
+        assertEquals("user", r.getUser());
+        assertEquals("2016-03-27", r.getUsageDate());
+        assertEquals("Amazon Elastic Compute Cloud", r.getProduct());
+        assertEquals("usageType", r.getUsageType());
+        assertEquals(56.7, r.getUsage());
+        assertEquals(1234.56789, r.getCost());
+        assertEquals("USD", r.getCurrencyCode());
+        assertEquals(BillingResourceType.COMPUTER, r.getResourceType());
+        assertEquals("i-1234567890abcdefg", r.getResourceId());
+        assertEquals("value1", r.getTags().get("sCol4"));
+        assertEquals("value2", r.getTags().get("sCol3"));
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/core/parser/ConditionEvaluateTest.java b/services/billing-aws/src/test/java/com/epam/datalab/core/parser/ConditionEvaluateTest.java
new file mode 100644
index 0000000..87e4eff
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/core/parser/ConditionEvaluateTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.datalab.core.parser;
+
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.exceptions.ParseException;
+import com.google.common.collect.Lists;
+import org.junit.Test;
+
+import java.util.List;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class ConditionEvaluateTest {
+    private static final List<String> columnNames = Lists.newArrayList("column1", "column2", "column3");
+
+    private void checkCondition(boolean excpectedResult, String condition, String... values
+    ) throws InitializationException, ParseException {
+        ConditionEvaluate c = new ConditionEvaluate(columnNames, condition);
+        final List<String> row = Lists.newArrayList(values);
+        assertEquals(excpectedResult, c.evaluate(row));
+    }
+
+    private void isTrue(String condition, String... values
+    ) throws InitializationException, ParseException {
+        checkCondition(true, condition, values);
+    }
+
+    private void isFalse(String condition, String... values
+    ) throws InitializationException, ParseException {
+        checkCondition(false, condition, values);
+    }
+
+    @Test
+    public void mixCondition() throws InitializationException, ParseException {
+        String condition = "column1 == 123 && column2 == '456' && column3 > 0.2";
+        ConditionEvaluate c = new ConditionEvaluate(columnNames, condition);
+
+        List<String> row = Lists.newArrayList("123", "456", "0.5");
+        assertEquals(true, c.evaluate(row));
+
+        row = Lists.newArrayList("123", "456", "-5");
+        assertEquals(false, c.evaluate(row));
+
+        isFalse("column1 == 123 || column2 == 321", "321", "123");
+        isTrue("column1 == 123 || column2 == 321", "123", "456");
+        isTrue("column1 == 123 || column2 == 321", "456", "321");
+
+        isFalse("(column1 == 123 || column2 == 321) && column3 == 5", "321", "123", "5");
+        isFalse("(column1 == 123 || column2 == 321) && column3 == 5", "123", "321", "4");
+
+        isTrue("(column1 == 123 || column2 == 321) && column3 == 5", "123", "456", "5");
+        isTrue("(column1 == 123 || column2 == 321) && column3 == 5", "234", "321", "5");
+    }
+
+    @Test
+    public void compareInteger() throws InitializationException, ParseException {
+        isFalse("column1 == 123", "456");
+        isTrue("column1 == 123", "123");
+
+        isFalse("column1 != 123", "123");
+        isTrue("column1 != 123", "456");
+
+        isFalse("column1 < 123", "123");
+        isTrue("column1 < 123", "122");
+
+        isFalse("column1 > 123", "123");
+        isTrue("column1 > 123", "124");
+
+        isFalse("column1 <= 123", "124");
+        isTrue("column1 <= 123", "123");
+        isTrue("column1 <= 123", "122");
+
+        isFalse("column1 >= 123", "122");
+        isTrue("column1 >= 123", "123");
+        isTrue("column1 >= 123", "124");
+    }
+
+    @Test
+    public void compareString() throws InitializationException, ParseException {
+        isFalse("column1 == 'abc'", "abcd");
+        isTrue("column1 == 'abc'", "abc");
+
+        isFalse("column1 != 'abc'", "abc");
+        isTrue("column1 != 'abc'", "asd");
+
+        isFalse("column1 < 'abc'", "abd");
+        isTrue("column1 < 'abc'", "abb");
+
+        isFalse("column1 > 'abc'", "abb");
+        isTrue("column1 > 'abc'", "abd");
+
+        isFalse("column1 <= 'abc'", "abd");
+        isTrue("column1 <= 'abc'", "abc");
+        isTrue("column1 <= 'abc'", "abb");
+
+        isFalse("column1 >= 'abc'", "abb");
+        isTrue("column1 >= 'abc'", "abc");
+        isTrue("column1 >= 'abc'", "abd");
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/core/parser/ReportLineTest.java b/services/billing-aws/src/test/java/com/epam/datalab/core/parser/ReportLineTest.java
new file mode 100644
index 0000000..f599abf
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/core/parser/ReportLineTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.datalab.core.parser;
+
+import com.epam.datalab.core.BillingUtils;
+import com.epam.datalab.exceptions.ParseException;
+import com.epam.datalab.model.aws.BillingResourceType;
+import com.epam.datalab.model.aws.ReportLine;
+import com.google.common.collect.Maps;
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class ReportLineTest {
+
+    private void checkGetters(ReportLine r) {
+        assertEquals("datalabId", r.getDatalabId());
+        assertEquals("user", r.getUser());
+        assertEquals("2016-01-22", r.getUsageDate());
+        assertEquals("Amazon Elastic Compute Cloud", r.getProduct());
+        assertEquals("usageType", r.getUsageType());
+        assertEquals(56.7, r.getUsage());
+        assertEquals(12.34, r.getCost());
+        assertEquals("USD", r.getCurrencyCode());
+        assertEquals("i-1234567890abcdefg", r.getResourceId());
+        assertEquals("value1", r.getTags().get("tag1"));
+        assertEquals("value2", r.getTags().get("tag2"));
+    }
+
+    @Test
+    public void set() throws ParseException {
+        ReportLine r = new ReportLine();
+
+        r.setDatalabId("datalabId");
+        r.setCost(12.34);
+        r.setCurrencyCode("USD");
+        r.setProduct("Amazon Elastic Compute Cloud");
+        r.setResourceTypeId("i-1234567890abcdefg");
+        r.setUsage(56.7);
+        r.setUsageDate("2016-01-22");
+        r.setUsageType("usageType");
+        r.setUser("user");
+        r.setTags(Maps.newLinkedHashMap(BillingUtils.stringsToMap("tag1", "value1", "tag2", "value2")));
+
+        checkGetters(r);
+    }
+
+    private void checkResourceType(String product, String resourceTypeId,
+                                   BillingResourceType expectedResourceType, String expectedResourceId) throws
+            ParseException {
+        ReportLine r = new ReportLine();
+        r.setProduct(product);
+        r.setResourceTypeId(resourceTypeId);
+
+        assertEquals(expectedResourceType, r.getResourceType());
+        assertEquals(expectedResourceId, r.getResourceId());
+    }
+
+    @Test
+    public void resourceType() throws ParseException {
+        checkResourceType("Amazon Elastic Compute Cloud", "i-000c0e51d117e3b4a", BillingResourceType.COMPUTER,
+                "i-000c0e51d117e3b4a");
+        checkResourceType("Amazon Elastic Compute Cloud", "vol-04c20f339836c56b6", BillingResourceType.STORAGE_EBS,
+                "vol-04c20f339836c56b6");
+        checkResourceType("Amazon Elastic Compute Cloud", "34.208.106.54", BillingResourceType.IP_ADDRESS,
+                "34.208.106.54");
+
+        checkResourceType("Amazon Elastic MapReduce",
+                "arn:aws:elasticmapreduce:us-west-2:203753054073:cluster/j-1FOBGFRC8X4XY", BillingResourceType
+                        .CLUSTER, "j-1FOBGFRC8X4XY");
+
+        checkResourceType("Amazon Simple Storage Service", "datalab-s3", BillingResourceType.STORAGE_BUCKET, "datalab-s3");
+        checkResourceType("AmazonCloudWatch",
+                "arn:aws:logs:us-west-2:203753054073:log-group:CloudTrail/DefaultLogGroup", BillingResourceType.OTHER,
+                "arn:aws:logs:us-west-2:203753054073:log-group:CloudTrail/DefaultLogGroup");
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/logging/AppenderConsoleTest.java b/services/billing-aws/src/test/java/com/epam/datalab/logging/AppenderConsoleTest.java
new file mode 100644
index 0000000..4785c8c
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/logging/AppenderConsoleTest.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.datalab.logging;
+
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class AppenderConsoleTest {
+
+    @Test
+    public void config() {
+        AppenderConsole appender = new AppenderConsole();
+        assertEquals("console", appender.getType());
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/logging/AppenderFileTest.java b/services/billing-aws/src/test/java/com/epam/datalab/logging/AppenderFileTest.java
new file mode 100644
index 0000000..30e941d
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/logging/AppenderFileTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.logging;
+
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class AppenderFileTest {
+
+    @Test
+    public void config() {
+        AppenderFile appender = new AppenderFile();
+        appender.setArchive(true);
+        appender.setArchivedFileCount(123);
+        appender.setArchivedLogFilenamePattern("file.log.zip");
+        appender.setCurrentLogFilename("file.log");
+
+        assertEquals("file", appender.getType());
+        assertEquals(true, appender.getArchive());
+        assertEquals(123, appender.getArchivedFileCount());
+        assertEquals("file.log.zip", appender.getArchivedLogFilenamePattern());
+        assertEquals("file.log", appender.getCurrentLogFilename());
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/module/AdapterConsoleTest.java b/services/billing-aws/src/test/java/com/epam/datalab/module/AdapterConsoleTest.java
new file mode 100644
index 0000000..40a9f09
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/module/AdapterConsoleTest.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.datalab.module;
+
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class AdapterConsoleTest {
+
+    @Test
+    public void config() {
+        AdapterConsole adapter = new AdapterConsole();
+        assertEquals(ModuleName.ADAPTER_CONSOLE, adapter.getType());
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/module/AdapterFileTest.java b/services/billing-aws/src/test/java/com/epam/datalab/module/AdapterFileTest.java
new file mode 100644
index 0000000..3cbd128
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/module/AdapterFileTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.datalab.module;
+
+import com.epam.datalab.core.AdapterBase.Mode;
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class AdapterFileTest {
+
+    @Test
+    public void config() {
+        AdapterFile adapter = new AdapterFile();
+        adapter.setMode(Mode.READ);
+        adapter.setWriteHeader(true);
+        adapter.setFile("filename");
+
+        assertEquals(ModuleName.ADAPTER_FILE, adapter.getType());
+        assertEquals(Mode.READ, adapter.getMode());
+        assertEquals(true, adapter.isWriteHeader());
+        assertEquals("filename", adapter.getFile());
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/module/AdapterMongoDBTest.java b/services/billing-aws/src/test/java/com/epam/datalab/module/AdapterMongoDBTest.java
new file mode 100644
index 0000000..7984520
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/module/AdapterMongoDBTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.datalab.module;
+
+import com.epam.datalab.core.AdapterBase.Mode;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.mongo.AdapterMongoDb;
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class AdapterMongoDBTest {
+
+    @Test
+    public void config() throws InitializationException {
+        AdapterMongoDb adapter = new AdapterMongoDb();
+        adapter.setMode(Mode.WRITE);
+        adapter.setWriteHeader(false);
+        adapter.setHost("host");
+        adapter.setPort(123);
+        adapter.setDatabase("database");
+        adapter.setUsername("username");
+        adapter.setPassword("password");
+        adapter.setBufferSize(321);
+        adapter.setUpsert(true);
+
+        assertEquals(ModuleName.ADAPTER_MONGO_DATALAB, adapter.getType());
+        assertEquals(Mode.WRITE, adapter.getMode());
+        assertEquals(false, adapter.isWriteHeader());
+        assertEquals("host", adapter.getHost());
+        assertEquals(123, adapter.getPort());
+        assertEquals("database", adapter.getDatabase());
+        assertEquals("username", adapter.getUsername());
+        assertEquals("password", adapter.getPassword());
+        assertEquals(321, adapter.getBufferSize());
+        assertEquals(true, adapter.isUpsert());
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/module/ParserCsvTest.java b/services/billing-aws/src/test/java/com/epam/datalab/module/ParserCsvTest.java
new file mode 100644
index 0000000..e3ed1e9
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/module/ParserCsvTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.datalab.module;
+
+import com.epam.datalab.core.aggregate.AggregateGranularity;
+import com.epam.datalab.exceptions.InitializationException;
+import com.epam.datalab.exceptions.ParseException;
+import com.epam.datalab.module.aws.FilterAWS;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.Lists;
+import org.junit.Test;
+
+import java.util.List;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class ParserCsvTest {
+
+    @Test
+    public void config() throws InitializationException {
+        ParserCsv parser = new ParserCsv();
+
+        parser.setFieldSeparator('a');
+        parser.setFieldTerminator('b');
+        parser.setEscapeChar('c');
+        parser.setDecimalSeparator('d');
+        parser.setGroupingSeparator('e');
+        parser.setAggregate(AggregateGranularity.DAY.toString());
+        parser.setColumnMapping("ColumnMapping");
+        parser.setHeaderLineNo(123);
+        parser.setSkipLines(321);
+
+        assertEquals(ModuleName.PARSER_CSV, parser.getType());
+        assertEquals('a', parser.getFieldSeparator());
+        assertEquals('b', parser.getFieldTerminator());
+        assertEquals('c', parser.getEscapeChar());
+        assertEquals('d', parser.getDecimalSeparator());
+        assertEquals('e', parser.getGroupingSeparator());
+        assertEquals(AggregateGranularity.DAY, parser.getAggregate());
+        assertEquals("ColumnMapping", parser.getColumnMapping());
+        assertEquals(123, parser.getHeaderLineNo());
+        assertEquals(321, parser.getSkipLines());
+
+        AdapterConsole adapterIn = new AdapterConsole();
+        AdapterConsole adapterOut = new AdapterConsole();
+        FilterAWS filter = new FilterAWS();
+        parser.build(adapterIn, adapterOut, filter);
+
+        assertEquals(adapterIn, parser.getAdapterIn());
+        assertEquals(adapterOut, parser.getAdapterOut());
+        assertEquals(filter, parser.getFilter());
+
+        parser.initialize();
+    }
+
+    @Test
+    public void parseRow() throws ParseException {
+        ParserCsv parser = new ParserCsv();
+        final List<String> row = Lists.newArrayList("qwe", "rty", "\"uio\"", "asd\"fgh\"jkl");
+        final String line = "\"qwe\",\"rty\",\"\\\"uio\\\"\",\"asd\\\"fgh\\\"jkl\"";
+        List<String> rowParsed = parser.parseRow(line);
+        assertEquals(MoreObjects.toStringHelper(this).add("row", row).toString(), MoreObjects.toStringHelper(this).add("row", rowParsed).toString());
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/module/aws/AdapterS3FileTest.java b/services/billing-aws/src/test/java/com/epam/datalab/module/aws/AdapterS3FileTest.java
new file mode 100644
index 0000000..318fb1f
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/module/aws/AdapterS3FileTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.datalab.module.aws;
+
+import com.epam.datalab.core.AdapterBase.Mode;
+import com.epam.datalab.module.ModuleName;
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class AdapterS3FileTest {
+
+    @Test
+    public void config() {
+        AdapterS3File adapter = new AdapterS3File();
+        adapter.setMode(Mode.READ);
+        adapter.setWriteHeader(true);
+        adapter.setBucket("bucket");
+        adapter.setPath("path");
+        adapter.setAccountId("accountId");
+        adapter.setAccessKeyId("accessKeyId");
+        adapter.setSecretAccessKey("secretAccessKey");
+
+        assertEquals(ModuleName.ADAPTER_S3_FILE, adapter.getType());
+        assertEquals(Mode.READ, adapter.getMode());
+        assertEquals(true, adapter.isWriteHeader());
+        assertEquals("bucket", adapter.getBucket());
+        assertEquals("path", adapter.getPath());
+        assertEquals("accountId", adapter.getAccountId());
+        assertEquals("accessKeyId", adapter.getAccessKeyId());
+        assertEquals("secretAccessKey", adapter.getSecretAccessKey());
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/module/aws/FilterAWSTest.java b/services/billing-aws/src/test/java/com/epam/datalab/module/aws/FilterAWSTest.java
new file mode 100644
index 0000000..f6dfd17
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/module/aws/FilterAWSTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.datalab.module.aws;
+
+import com.epam.datalab.exceptions.ParseException;
+import com.epam.datalab.model.aws.ReportLine;
+import com.epam.datalab.module.ModuleName;
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class FilterAWSTest {
+
+    @Test
+    public void config() {
+        FilterAWS filter = new FilterAWS();
+        filter.setCurrencyCode("currency");
+
+        assertEquals(ModuleName.FILTER_AWS, filter.getType());
+        assertEquals("currency", filter.getCurrencyCode());
+    }
+
+    @Test
+    public void canAccept() throws ParseException {
+        FilterAWS filter = new FilterAWS();
+        filter.setCurrencyCode("currency");
+
+        ReportLine row = new ReportLine();
+        row = filter.canAccept(row);
+
+        assertEquals(filter.getCurrencyCode(), row.getCurrencyCode());
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/datalab/module/aws/S3FileListTest.java b/services/billing-aws/src/test/java/com/epam/datalab/module/aws/S3FileListTest.java
new file mode 100644
index 0000000..da38bb8
--- /dev/null
+++ b/services/billing-aws/src/test/java/com/epam/datalab/module/aws/S3FileListTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.datalab.module.aws;
+
+import com.amazonaws.services.s3.AmazonS3Client;
+import com.amazonaws.services.s3.model.ListObjectsV2Request;
+import com.amazonaws.services.s3.model.ListObjectsV2Result;
+import com.amazonaws.services.s3.model.S3ObjectSummary;
+import com.epam.datalab.core.ModuleData;
+import com.epam.datalab.exceptions.AdapterException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.sql.Date;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.Arrays;
+import java.util.List;
+
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.TestCase.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class S3FileListTest {
+
+    @Test
+    public void sort() throws AdapterException {
+        final AmazonS3Client s3Client = mock(AmazonS3Client.class);
+        final ListObjectsV2Result result = mock(ListObjectsV2Result.class);
+        final ModuleData moduleData = mock(ModuleData.class);
+        final String[] array = {
+                "report-prefix/report/20160101-20160131/123456789/report-1.csv",
+                "report-prefix/report/20160101-20160131/123456789/report-2.csv",
+                "report-prefix/report/20160101-20160131/123456789/report-3.csv",
+                "report-prefix/report/20160202-20160231/123456789/report.csv",
+                "report-prefix/report/20160202-20160301/123456789/report.csv",
+                "report-prefix/report/20160303-20160301/123456789/report-1.csv",
+                "report-prefix/report/20160303-20160301/123456789/report-2.csv",
+                "report-prefix/report/20160303-20160302/123456789/report-1.csv",
+                "report-prefix/report/20160303-20160302/123456789/report-2.csv"
+        };
+        final List<S3ObjectSummary> objectSummaries = Arrays.asList(
+                getObjectSummary(array[0], LocalDate.of(2018, 4, 4)),
+                getObjectSummary(array[4], LocalDate.of(2018, 4, 4)),
+                getObjectSummary(array[1], LocalDate.of(2018, 4, 4)),
+                getObjectSummary(array[2], LocalDate.of(2018, 4, 4)),
+                getObjectSummary(array[3], LocalDate.of(2018, 4, 4)),
+                getObjectSummary(array[5], LocalDate.of(2018, 4, 4)),
+                getObjectSummary(array[6], LocalDate.of(2018, 4, 4)),
+                getObjectSummary(array[7], LocalDate.of(2018, 4, 4)),
+                getObjectSummary(array[8], LocalDate.of(2018, 4, 4))
+
+        );
+        when(s3Client.listObjectsV2(any(ListObjectsV2Request.class))).thenReturn(result);
+        when(result.getObjectSummaries()).thenReturn(objectSummaries);
+        when(moduleData.wasProcessed(any(), any(), anyString())).thenReturn(false);
+
+        S3FileList s3list = new S3FileList(false, "test", moduleData);
+        final List<String> list = s3list.getFiles(s3Client);
+
+        assertEquals(array.length, list.size());
+        for (int i = 0; i < array.length; i++) {
+            assertEquals(array[i], list.get(i));
+        }
+    }
+
+    @Test
+    public void testGettingLastFilesInBillingPeriod() throws Exception {
+        final ListObjectsV2Result result = mock(ListObjectsV2Result.class);
+        final ModuleData moduleData = mock(ModuleData.class);
+        final List<S3ObjectSummary> objectSummaries = Arrays.asList(
+                getObjectSummary("DATALAB-billing/reportName/20180101-20180201/guid1/test-1.csv.zip",
+                        LocalDate.of(2018, 4, 1)),
+                getObjectSummary("DATALAB-billing/reportName/20180101-20180201/guid1/test-2.csv.zip",
+                        LocalDate.of(2018, 4, 1)),
+                getObjectSummary("DATALAB-billing/reportName/20180101-20180201/guid0/test-1.csv.zip",
+                        LocalDate.of(2018, 1, 1)),
+                getObjectSummary("DATALAB-billing/reportName/20180201-20180301/guid0/test-1.csv.zip",
+                        LocalDate.of(2018, 1, 1)),
+                getObjectSummary("DATALAB-billing/reportName/20180202-20180301/guid0/test-2.csv.zip",
+                        LocalDate.of(2018, 1, 1))
+
+        );
+        when(result.getObjectSummaries()).thenReturn(objectSummaries);
+        final List<String> files = new S3FileList(true, null, moduleData).lastFilesPerBillingPeriod(result
+                .getObjectSummaries());
+
+        assertEquals(4, files.size());
+        assertTrue(files.contains("DATALAB-billing/reportName/20180101-20180201/guid1/test-1.csv.zip"));
+        assertTrue(files.contains("DATALAB-billing/reportName/20180101-20180201/guid1/test-2.csv.zip"));
+        assertTrue(files.contains("DATALAB-billing/reportName/20180201-20180301/guid0/test-1.csv.zip"));
+        assertTrue(files.contains("DATALAB-billing/reportName/20180202-20180301/guid0/test-2.csv.zip"));
+
+
+    }
+
+    private S3ObjectSummary getObjectSummary(String key, LocalDate modificationDate) {
+        final S3ObjectSummary objectSummary = new S3ObjectSummary();
+        objectSummary.setKey(key);
+        objectSummary.setLastModified(Date.from(modificationDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
+        return objectSummary;
+    }
+}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/configuration/BillingToolConfigurationTest.java b/services/billing-aws/src/test/java/com/epam/dlab/configuration/BillingToolConfigurationTest.java
deleted file mode 100644
index 4577516..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/configuration/BillingToolConfigurationTest.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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.configuration;
-
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertNotNull;
-
-import org.junit.Ignore;
-import org.junit.Test;
-
-import com.epam.dlab.core.AdapterBase.Mode;
-import com.epam.dlab.core.aggregate.AggregateGranularity;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.module.AdapterConsole;
-import com.epam.dlab.module.AdapterFile;
-import com.epam.dlab.module.ModuleName;
-import com.epam.dlab.module.ParserCsv;
-import com.epam.dlab.module.aws.FilterAWS;
-import com.fasterxml.jackson.databind.JsonNode;
-
-public class BillingToolConfigurationTest {
-
-	@Test
-	@Ignore
-	public void config() throws InitializationException {
-		JsonNode node = new ConfigJsonGenerator()
-				.withAdapterIn("type", ModuleName.ADAPTER_FILE,
-								"file", "fileIn.csv")
-				.withAdapterOut("type", ModuleName.ADAPTER_CONSOLE)
-				.withFilter("type", ModuleName.FILTER_AWS,
-							"currencyCode", "USD",
-							"columnDlabTag", "user:user:tag",
-							"serviceBaseName", "sbn")
-				.withParser("type", ModuleName.PARSER_CSV,
-							"columnMapping", "dlab_id=user:user:tag;usage_date=UsageStartDate;product=ProductName;" +
-											"tags=Operation,ItemDescription",
-							"whereCondition", "UsageStartDate >= '2017-04-12'",
-							"aggregate", "day",
-							"headerLineNo", "5",
-							"skipLines", "10",
-							"fieldSeparator", ";",
-							"fieldTerminator", "^",
-							"escapeChar", "/",
-							"decimalSeparator", ",",
-							"groupingSeparator", "_")
-				.build();
-		BillingToolConfiguration conf = BillingToolConfigurationFactory.build(node, BillingToolConfiguration.class);
-		ParserCsv parser = (ParserCsv) conf.build();
-		
-		assertNotNull("Parser was not build", parser);
-		
-		AdapterFile in = (AdapterFile) parser.getAdapterIn();
-		assertEquals(ModuleName.ADAPTER_FILE, in.getType());
-		assertEquals(Mode.READ, in.getMode());
-		assertEquals("fileIn.csv", in.getFile());
-		
-		AdapterConsole out = (AdapterConsole) parser.getAdapterOut();
-		assertEquals(ModuleName.ADAPTER_CONSOLE, out.getType());
-		assertEquals(Mode.WRITE, out.getMode());
-		
-		FilterAWS filter = (FilterAWS) parser.getFilter();
-		assertEquals(ModuleName.FILTER_AWS, filter.getType());
-		assertEquals("USD", filter.getCurrencyCode());
-		assertEquals("user:user:tag", filter.getColumnDlabTag());
-		assertEquals("sbn", filter.getServiceBaseName());
-		assertEquals(parser, filter.getParser());
-		
-		assertEquals(ModuleName.PARSER_CSV, parser.getType());
-		assertEquals("dlab_id=user:user:tag;usage_date=UsageStartDate;product=ProductName;tags=Operation,ItemDescription",
-				parser.getColumnMapping());
-		assertEquals("UsageStartDate >= '2017-04-12'", parser.getWhereCondition());
-		assertEquals(AggregateGranularity.DAY, parser.getAggregate());
-		assertEquals(5, parser.getHeaderLineNo());
-		assertEquals(10, parser.getSkipLines());
-		assertEquals(';', parser.getFieldSeparator());
-		assertEquals('^', parser.getFieldTerminator());
-		assertEquals('/', parser.getEscapeChar());
-		assertEquals(',', parser.getDecimalSeparator());
-		assertEquals('_', parser.getGroupingSeparator());
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/configuration/ConfigJsonGeneratorTest.java b/services/billing-aws/src/test/java/com/epam/dlab/configuration/ConfigJsonGeneratorTest.java
deleted file mode 100644
index 15d3224..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/configuration/ConfigJsonGeneratorTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.configuration;
-
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertNotNull;
-
-import java.io.IOException;
-
-import org.junit.Test;
-
-import com.fasterxml.jackson.databind.JsonNode;
-
-public class ConfigJsonGeneratorTest {
-	
-	private void checkProperty(JsonNode conf, String module, String name, String expectedValue) {
-		JsonNode m = conf.get(module);
-		assertNotNull("Module \"" + module + "\" not found in JSON configuration", m);
-		
-		JsonNode item = m.get(0);
-		assertNotNull("Property \"" + module + "." + name + "\" not found in JSON configuration", item);
-		
-		JsonNode p = item.get(name);
-		assertNotNull("Property \"" + module + "." + name + "\" not found in JSON configuration", p);
-		
-		assertEquals(expectedValue, p.asText());
-	}
-
-	@Test
-	public void build() throws IOException {
-		JsonNode conf = new ConfigJsonGenerator()
-				.withAdapterIn("adapterInProperty", "adapterInValue")
-				.withAdapterOut("adapterOutProperty", "adapterOutValue")
-				.withParser("parserProperty", "parserValue")
-				.withFilter("filterProperty", "filterValue")
-				.build();
-		
-		checkProperty(conf, "adapterIn", "adapterInProperty", "adapterInValue");
-		checkProperty(conf, "adapterOut", "adapterOutProperty", "adapterOutValue");
-		checkProperty(conf, "parser", "parserProperty", "parserValue");
-		checkProperty(conf, "filter", "filterProperty", "filterValue");
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/configuration/ConfigurationValidatorTest.java b/services/billing-aws/src/test/java/com/epam/dlab/configuration/ConfigurationValidatorTest.java
deleted file mode 100644
index 9d75413..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/configuration/ConfigurationValidatorTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.configuration;
-
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.fail;
-
-import javax.validation.constraints.NotNull;
-
-import org.junit.Test;
-
-import com.epam.dlab.exceptions.InitializationException;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-public class ConfigurationValidatorTest {
-	
-	class TestProperty {
-		
-		@JsonProperty
-		@NotNull
-		String property;
-	}
-	
-	@Test
-	public void validate() throws InitializationException {
-		ConfigurationValidator<TestProperty> v = new ConfigurationValidator<>();
-		TestProperty o = new TestProperty();
-		try {
-			v.validate(o);
-			fail("Property is null but validate is passed");
-		} catch (InitializationException e) {
-			// OK
-		}
-		o.property = "value";
-		v.validate(o);
-		assertEquals("value", o.property);
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/configuration/LoggingConfigurationFactoryTest.java b/services/billing-aws/src/test/java/com/epam/dlab/configuration/LoggingConfigurationFactoryTest.java
deleted file mode 100644
index 82f5ef5..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/configuration/LoggingConfigurationFactoryTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.configuration;
-
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertNotNull;
-
-import java.io.IOException;
-import java.util.List;
-
-import org.junit.Test;
-
-import com.epam.dlab.core.BillingUtils;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.logging.AppenderBase;
-import com.epam.dlab.logging.AppenderConsole;
-import com.epam.dlab.logging.AppenderFile;
-import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.datatype.guava.GuavaModule;
-
-import ch.qos.logback.classic.Level;
-
-public class LoggingConfigurationFactoryTest {
-	
-	private ObjectMapper getMapper() throws InitializationException {
-		ObjectMapper mapper = new ObjectMapper().enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
-		mapper.registerModule(new GuavaModule());
-    	for (Class<?> clazz : BillingUtils.getModuleClassList()) {
-			mapper.registerSubtypes(clazz);
-		}
-    	return mapper;
-	}
-
-	@Test
-	public void config() throws IOException, InitializationException {
-		// {"filter":[{"filterProperty":"filterValue"}],"parser":[{"parserProperty":"parserValue"}],"adapterIn":[{"adapterInProperty":"adapterInValue"}],"adapterOut":[{"adapterOutProperty":"adapterOutValue"}]}
-		final String jsonString =
-			"{\n" +
-			"  \"level\":\"INFO\",\n" +
-			"  \"loggers\":{\n" +
-			"    \"com.epam\":\"DEBUG\",\n" +
-			"    \"org.apache.http\":\"WARN\"},\n" +
-			"  \"appenders\":[\n" +
-			"    {\"type\":\"console\"},\n" +
-			"    {\"type\":\"file\",\n" +
-			"      \"currentLogFilename\":\"billing.log\",\n" +
-			"      \"archive\":true,\n" +
-			"      \"archivedLogFilenamePattern\":\"billing-%d{yyyy-MM-dd}.log.gz\",\n" +
-			"      \"archivedFileCount\":10}]\n" +
-			"}";
-		
-		ObjectMapper mapper = getMapper();
-		JsonNode conf = mapper.readTree(jsonString); // validate JSON
-		LoggingConfigurationFactory logger = mapper.readValue(conf.toString(), LoggingConfigurationFactory.class);
-		
-		assertEquals(Level.INFO, logger.getLevel());
-		assertEquals(Level.DEBUG, logger.getLoggers().get("com.epam"));
-		assertEquals(Level.WARN, logger.getLoggers().get("org.apache.http"));
-		
-		List<AppenderBase> appenders = logger.getAppenders();
-		assertEquals("Invalid number of appenders", 2, appenders.size());
-		
-		AppenderConsole ac = (AppenderConsole) appenders.get(0);
-		assertNotNull(ac);
-		
-		AppenderFile af = (AppenderFile) appenders.get(1);
-		assertEquals("billing.log", af.getCurrentLogFilename());
-		assertEquals(true, af.getArchive());
-		assertEquals("billing-%d{yyyy-MM-dd}.log.gz", af.getArchivedLogFilenamePattern());
-		assertEquals(10, af.getArchivedFileCount());
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/core/BillingUtilsTest.java b/services/billing-aws/src/test/java/com/epam/dlab/core/BillingUtilsTest.java
deleted file mode 100644
index 70d1127..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/core/BillingUtilsTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.core;
-
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.fail;
-
-import java.util.List;
-import java.util.Map;
-
-import org.junit.Test;
-
-import com.epam.dlab.core.parser.ParserBase;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.logging.AppenderBase;
-import com.epam.dlab.logging.AppenderConsole;
-import com.epam.dlab.logging.AppenderFile;
-import com.epam.dlab.module.AdapterConsole;
-import com.epam.dlab.module.AdapterFile;
-import com.epam.dlab.module.ParserCsv;
-import com.epam.dlab.module.aws.AdapterS3File;
-import com.epam.dlab.module.aws.FilterAWS;
-import com.epam.dlab.mongo.AdapterMongoDb;
-
-public class BillingUtilsTest {
-	
-	@Test
-	public void stringsToMap() {
-		Map<String, String> map = BillingUtils.stringsToMap(
-				"key1", "value1",
-				"key2", "value2");
-		assertEquals(2, map.size());
-		assertEquals("value1", map.get("key1"));
-		assertEquals("value2", map.get("key2"));
-		
-		try {
-			map = BillingUtils.stringsToMap(
-				"key1", "value1",
-				"key2");
-			fail("Missed value2 is passed");
-		} catch (IllegalArgumentException e) {
-			// OK
-		}
-	}
-	
-	private void checkModule(List<Class<?>> list, Class<?> moduleClass) {
-		for (Class<?> module : list) {
-			if (module == moduleClass) {
-				return;
-			}
-		}
-		fail("Module " + moduleClass.getName() + " is not in module list");
-	}
-	
-	@Test
-	public void getModuleClassList() throws InitializationException {
-		List<Class<?>> list = BillingUtils.getModuleClassList();
-		checkModule(list, AdapterConsole.class);
-		checkModule(list, AdapterFile.class);
-		checkModule(list, AdapterS3File.class);
-		checkModule(list, AdapterMongoDb.class);
-		checkModule(list, FilterAWS.class);
-		checkModule(list, ParserCsv.class);
-		checkModule(list, AppenderConsole.class);
-		checkModule(list, AppenderFile.class);
-	}
-	
-	@Test
-	public void classChildOf() {
-		assertEquals(true, BillingUtils.classChildOf(AdapterConsole.class, AdapterBase.class));
-		assertEquals(false, BillingUtils.classChildOf(AdapterConsole.class, FilterBase.class));
-		assertEquals(true, BillingUtils.classChildOf(FilterAWS.class, FilterBase.class));
-		assertEquals(false, BillingUtils.classChildOf(FilterAWS.class, ParserBase.class));
-		assertEquals(true, BillingUtils.classChildOf(ParserCsv.class, ParserBase.class));
-		assertEquals(false, BillingUtils.classChildOf(ParserCsv.class, AppenderBase.class));
-		assertEquals(true, BillingUtils.classChildOf(AppenderConsole.class, AppenderBase.class));
-		assertEquals(false, BillingUtils.classChildOf(AppenderConsole.class, AdapterBase.class));
-	}
-	
-	@Test
-	public void getModuleType() {
-		assertEquals(ModuleType.ADAPTER, BillingUtils.getModuleType(AdapterConsole.class));
-		assertEquals(ModuleType.ADAPTER, BillingUtils.getModuleType(AdapterFile.class));
-		assertEquals(ModuleType.ADAPTER, BillingUtils.getModuleType(AdapterS3File.class));
-		assertEquals(ModuleType.ADAPTER, BillingUtils.getModuleType(AdapterMongoDb.class));
-		assertEquals(ModuleType.FILTER, BillingUtils.getModuleType(FilterAWS.class));
-		assertEquals(ModuleType.PARSER, BillingUtils.getModuleType(ParserCsv.class));
-		assertEquals(ModuleType.LOGAPPENDER, BillingUtils.getModuleType(AppenderConsole.class));
-		assertEquals(ModuleType.LOGAPPENDER, BillingUtils.getModuleType(AppenderFile.class));
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/core/aggregate/DataAggregatorTest.java b/services/billing-aws/src/test/java/com/epam/dlab/core/aggregate/DataAggregatorTest.java
deleted file mode 100644
index d77ef71..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/core/aggregate/DataAggregatorTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.core.aggregate;
-
-import static junit.framework.TestCase.assertEquals;
-
-import org.junit.Test;
-
-public class DataAggregatorTest {
-
-	@Test
-	public void append() {
-		UsageDataList list = new UsageDataList();
-		
-		list.append("2017-04-12");
-		list.append("2017-04-12");
-		list.append("2017-04-14");
-		
-		assertEquals(2, list.size());
-		
-		assertEquals(Boolean.FALSE, list.get("2017-04-12"));
-		assertEquals(Boolean.FALSE, list.get("2017-04-14"));
-		
-		list.set("2017-04-14", true);
-		assertEquals(Boolean.TRUE, list.get("2017-04-14"));
-		
-		list.clear();
-		assertEquals(0, list.size());
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/core/aggregate/UsageDataListTest.java b/services/billing-aws/src/test/java/com/epam/dlab/core/aggregate/UsageDataListTest.java
deleted file mode 100644
index 275a30b..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/core/aggregate/UsageDataListTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.core.aggregate;
-
-import com.epam.dlab.model.aws.ReportLine;
-import org.junit.Test;
-
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.fail;
-
-public class UsageDataListTest {
-
-	@Test
-	public void day() {
-		DataAggregator agg = new DataAggregator(AggregateGranularity.DAY);
-		ReportLine r;
-
-		r = new ReportLine();
-		r.setUsageDate("2017-04-12 12:34:56");
-		r.setCost(1.2);
-		r.setUsage(10.1);
-		agg.append(r);
-
-		r = new ReportLine();
-		r.setUsageDate("2017-04-12 12:34:78");
-		r.setCost(3.4);
-		r.setUsage(20.2);
-		agg.append(r);
-
-		r = new ReportLine();
-		r.setUsageDate("2017-04-14 11:22:33");
-		r.setCost(5.6);
-		r.setUsage(40.4);
-		agg.append(r);
-
-		assertEquals(AggregateGranularity.DAY, agg.getGranularity());
-		assertEquals(2, agg.size());
-
-		assertEquals("2017-04-12", agg.get(0).getUsageDate());
-		assertEquals(4.6, agg.get(0).getCost());
-		assertEquals(30.3, agg.get(0).getUsage(), 0.000001);
-
-		assertEquals("2017-04-14", agg.get(1).getUsageDate());
-		assertEquals(5.6, agg.get(1).getCost());
-		assertEquals(40.4, agg.get(1).getUsage());
-
-		agg.clear();
-		assertEquals(0, agg.size());
-	}
-
-	@Test
-	public void month() {
-		DataAggregator agg = new DataAggregator(AggregateGranularity.MONTH);
-		ReportLine r;
-
-		r = new ReportLine();
-		r.setUsageDate("2017-04-12 12:34:56");
-		r.setCost(1.2);
-		r.setUsage(10.1);
-		agg.append(r);
-
-		r = new ReportLine();
-		r.setUsageDate("2017-04-12 12:34:78");
-		r.setCost(3.4);
-		r.setUsage(20.2);
-		agg.append(r);
-
-		r = new ReportLine();
-		r.setUsageDate("2017-05-14 11:22:33");
-		r.setCost(5.6);
-		r.setUsage(40.4);
-		agg.append(r);
-
-		assertEquals(AggregateGranularity.MONTH, agg.getGranularity());
-		assertEquals(2, agg.size());
-
-		assertEquals("2017-04", agg.get(0).getUsageDate());
-		assertEquals(4.6, agg.get(0).getCost());
-		assertEquals(30.3, agg.get(0).getUsage(), 0.000001);
-
-		assertEquals("2017-05", agg.get(1).getUsageDate());
-		assertEquals(5.6, agg.get(1).getCost());
-		assertEquals(40.4, agg.get(1).getUsage());
-
-		agg.clear();
-		assertEquals(0, agg.size());
-	}
-
-	@Test
-	public void none() {
-		try {
-			new DataAggregator(AggregateGranularity.NONE);
-			fail("DataArggregator should not have been created");
-		} catch (IllegalArgumentException e) {
-			// OK
-		}
-	}
-
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/core/parser/BillingResourceTypeTest.java b/services/billing-aws/src/test/java/com/epam/dlab/core/parser/BillingResourceTypeTest.java
deleted file mode 100644
index 9aaa383..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/core/parser/BillingResourceTypeTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.core.parser;
-
-import com.epam.dlab.model.aws.BillingResourceType;
-import org.junit.Test;
-
-import static junit.framework.TestCase.assertEquals;
-
-public class BillingResourceTypeTest {
-	
-	@Test
-	public void test() {
-		BillingResourceType type = BillingResourceType.of("cluster");
-		
-		assertEquals(BillingResourceType.CLUSTER, type);
-		assertEquals(BillingResourceType.CLUSTER.toString(), "CLUSTER");
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/core/parser/ColumnInfoTest.java b/services/billing-aws/src/test/java/com/epam/dlab/core/parser/ColumnInfoTest.java
deleted file mode 100644
index adc1a5e..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/core/parser/ColumnInfoTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.core.parser;
-
-import static junit.framework.TestCase.assertEquals;
-
-import org.junit.Test;
-
-public class ColumnInfoTest {
-	
-	@Test
-	public void test() {
-		ColumnInfo ci = new ColumnInfo("target", "source", 123);
-		
-		assertEquals("target", ci.targetName);
-		assertEquals("source", ci.sourceName);
-		assertEquals(123, ci.sourceIndex);
-	}
-
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/core/parser/ColumnMetaTest.java b/services/billing-aws/src/test/java/com/epam/dlab/core/parser/ColumnMetaTest.java
deleted file mode 100644
index c03f87f..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/core/parser/ColumnMetaTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.core.parser;
-
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.google.common.collect.Lists;
-import org.junit.Test;
-
-import java.util.List;
-
-import static junit.framework.TestCase.assertEquals;
-
-public class ColumnMetaTest {
-
-	@Test
-	public void getColumnIndexByName() throws InitializationException {
-		final List<String> columns = Lists.newArrayList("sCol1", "sCol2", "sCol3", "sCol4");
-
-		assertEquals(0, ColumnMeta.getColumnIndexByName("sCol1", columns));
-		assertEquals(1, ColumnMeta.getColumnIndexByName("sCol2", columns));
-		assertEquals(3, ColumnMeta.getColumnIndexByName("sCol4", columns));
-
-		try {
-			ColumnMeta.getColumnIndexByName("NotFound", columns);
-
-			throw new RuntimeException("Test failed");
-		} catch (InitializationException e) {
-			// OK
-		}
-	}
-
-	private void checkMapping(ColumnInfo info, String targetColumnName, String sourceColumnName, int
-			sourceColumnIndex) {
-		assertEquals(targetColumnName, info.targetName);
-		assertEquals(sourceColumnName, info.sourceName);
-		assertEquals(sourceColumnIndex, info.sourceIndex);
-	}
-
-	@Test
-	public void create() throws InitializationException {
-		final String mapping =
-				ColumnMeta.COLUMN_NAMES[0] + "=sCol2;" +
-						ColumnMeta.COLUMN_NAMES[1] + "=$1;" +
-						ReportLine.FIELD_TAGS + "=sCol4,$3";
-		final List<String> columns = Lists.newArrayList("sCol1", "sCol2", "sCol3", "sCol4");
-		ColumnMeta meta = new ColumnMeta(mapping, columns);
-
-		assertEquals(4, meta.getSourceColumnNames().size());
-		assertEquals("sCol1", meta.getSourceColumnNames().get(0));
-		assertEquals("sCol2", meta.getSourceColumnNames().get(1));
-		assertEquals("sCol3", meta.getSourceColumnNames().get(2));
-		assertEquals("sCol4", meta.getSourceColumnNames().get(3));
-
-		assertEquals(ColumnMeta.COLUMN_NAMES.length + 1, meta.getTargetColumnNames().size());
-		assertEquals(ColumnMeta.COLUMN_NAMES[0], meta.getTargetColumnNames().get(0));
-		assertEquals("sCol4", meta.getTargetColumnNames().get(ColumnMeta.COLUMN_NAMES.length - 1));
-		assertEquals("sCol3", meta.getTargetColumnNames().get(ColumnMeta.COLUMN_NAMES.length));
-
-		assertEquals(ColumnMeta.COLUMN_NAMES.length + 1, meta.getColumnMapping().size());
-		checkMapping(meta.getColumnMapping().get(0), ColumnMeta.COLUMN_NAMES[0], "sCol2", 1);
-		checkMapping(meta.getColumnMapping().get(1), ColumnMeta.COLUMN_NAMES[1], "sCol1", 0);
-		checkMapping(meta.getColumnMapping().get(ColumnMeta.COLUMN_NAMES.length - 1), ColumnMeta
-				.COLUMN_NAMES[ColumnMeta.COLUMN_NAMES.length - 1], "sCol4", 3);
-		checkMapping(meta.getColumnMapping().get(ColumnMeta.COLUMN_NAMES.length), ColumnMeta.COLUMN_NAMES[ColumnMeta
-				.COLUMN_NAMES.length - 1], "sCol3", 2);
-	}
-
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/core/parser/CommonFormatTest.java b/services/billing-aws/src/test/java/com/epam/dlab/core/parser/CommonFormatTest.java
deleted file mode 100644
index 632fa96..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/core/parser/CommonFormatTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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.core.parser;
-
-import com.epam.dlab.core.BillingUtils;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.exceptions.ParseException;
-import com.epam.dlab.model.aws.BillingResourceType;
-import com.epam.dlab.model.aws.ReportLine;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import org.junit.Test;
-
-import java.util.List;
-
-import static junit.framework.TestCase.assertEquals;
-
-public class CommonFormatTest {
-
-	private CommonFormat getInstance() throws InitializationException {
-		final List<String> columns = Lists.newArrayList("sCol1", "sCol2", "sCol3", "sCol4");
-		final String mapping = ReportLine.FIELD_DLAB_ID + "=sCol2;" +
-				ReportLine.FIELD_USER_ID + "=$1;" + ReportLine.FIELD_TAGS + "=$4,sCol3";
-		ColumnMeta meta = new ColumnMeta(mapping, columns);
-		return new CommonFormat(meta, '.', ' ');
-	}
-
-	@Test
-	public void toCommonFormat() throws InitializationException, ParseException {
-		final CommonFormat format = getInstance();
-		final List<String> values = Lists.newArrayList("value1", "value2", "value3", "value4");
-		final ReportLine r = format.toCommonFormat(values);
-
-		assertEquals("value2", r.getDlabId());
-		assertEquals("value1", r.getUser());
-		assertEquals(2, r.getTags().size());
-		assertEquals("value4", r.getTags().get("sCol4"));
-		assertEquals("value3", r.getTags().get("sCol3"));
-
-		assertEquals(123456.789, format.parseDouble("column1", "123 456.789"));
-		assertEquals("12345.678", CommonFormat.doubleToString(12345.678));
-	}
-
-	@Test
-	public void rowToString() throws ParseException {
-		final List<String> values = Lists.newArrayList("val\"ue1", "\"val,;ue2\"", "value3", "value4");
-		String line = CommonFormat.rowToString(values);
-		assertEquals("\"val\\\"ue1\",\"\\\"val,;ue2\\\"\",\"value3\",\"value4\"", line);
-
-		final ReportLine r = new ReportLine();
-		r.setDlabId("accountId");
-		r.setUser("user");
-		r.setUsageDate("2016-03-20");
-		r.setProduct("Amazon Elastic Compute Cloud");
-		r.setUsageType("usageType");
-		r.setUsage(56.7);
-		r.setCost(1234.56789);
-		r.setCurrencyCode("USD");
-		r.setResourceTypeId("i-1234567890abcdefg");
-		r.setTags(Maps.newLinkedHashMap(BillingUtils.stringsToMap("tag1", "value1", "tag2", "value2")));
-		line = CommonFormat.rowToString(r);
-		assertEquals("\"accountId\",\"user\",\"2016-03-20\",\"Amazon Elastic Compute Cloud\"," +
-				"\"usageType\",\"56.7\",\"1234.56789\",\"USD\"," +
-				"\"COMPUTER\",\"i-1234567890abcdefg\"," +
-				"\"value1\",\"value2\"", line);
-	}
-
-	@Test
-	public void toReportLine() throws InitializationException, ParseException {
-		final CommonFormat format = getInstance();
-		final List<String> values = Lists.newArrayList(
-				"accountId", "user", "2016-03-27",
-				"Amazon Elastic Compute Cloud", "usageType", "56.7", "1234.56789", "USD",
-				"i-1234567890abcdefg", "value1", "value2");
-		final ReportLine r = format.toReportLine(values);
-
-		assertEquals("accountId", r.getDlabId());
-		assertEquals("user", r.getUser());
-		assertEquals("2016-03-27", r.getUsageDate());
-		assertEquals("Amazon Elastic Compute Cloud", r.getProduct());
-		assertEquals("usageType", r.getUsageType());
-		assertEquals(56.7, r.getUsage());
-		assertEquals(1234.56789, r.getCost());
-		assertEquals("USD", r.getCurrencyCode());
-		assertEquals(BillingResourceType.COMPUTER, r.getResourceType());
-		assertEquals("i-1234567890abcdefg", r.getResourceId());
-		assertEquals("value1", r.getTags().get("sCol4"));
-		assertEquals("value2", r.getTags().get("sCol3"));
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/core/parser/ConditionEvaluateTest.java b/services/billing-aws/src/test/java/com/epam/dlab/core/parser/ConditionEvaluateTest.java
deleted file mode 100644
index 548aa5c..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/core/parser/ConditionEvaluateTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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.core.parser;
-
-import static junit.framework.TestCase.assertEquals;
-
-import java.util.List;
-
-import org.junit.Test;
-
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.exceptions.ParseException;
-import com.google.common.collect.Lists;
-
-public class ConditionEvaluateTest {
-	private static final List<String> columnNames = Lists.newArrayList("column1", "column2", "column3");
-	
-	private void checkCondition(boolean excpectedResult, String condition, String ... values
-			) throws InitializationException, ParseException {
-		ConditionEvaluate c = new ConditionEvaluate(columnNames, condition);
-		final List<String> row = Lists.newArrayList(values);
-		assertEquals(excpectedResult, c.evaluate(row));
-	}
-
-	private void isTrue(String condition, String ... values
-			) throws InitializationException, ParseException {
-		checkCondition(true, condition, values);
-	}
-
-	private void isFalse(String condition, String ... values
-			) throws InitializationException, ParseException {
-		checkCondition(false, condition, values);
-	}
-
-	@Test
-	public void mixCondition() throws InitializationException, ParseException {
-		String condition = "column1 == 123 && column2 == '456' && column3 > 0.2";
-		ConditionEvaluate c = new ConditionEvaluate(columnNames, condition);
-		
-		List<String> row = Lists.newArrayList("123", "456", "0.5");
-		assertEquals(true, c.evaluate(row));
-		
-		row = Lists.newArrayList("123", "456", "-5");
-		assertEquals(false, c.evaluate(row));
-		
-		isFalse("column1 == 123 || column2 == 321", "321", "123");
-		isTrue("column1 == 123 || column2 == 321", "123", "456");
-		isTrue("column1 == 123 || column2 == 321", "456", "321");
-
-		isFalse("(column1 == 123 || column2 == 321) && column3 == 5", "321", "123", "5");
-		isFalse("(column1 == 123 || column2 == 321) && column3 == 5", "123", "321", "4");
-		
-		isTrue("(column1 == 123 || column2 == 321) && column3 == 5", "123", "456", "5");
-		isTrue("(column1 == 123 || column2 == 321) && column3 == 5", "234", "321", "5");
-	}
-
-	@Test
-	public void compareInteger() throws InitializationException, ParseException {
-		isFalse("column1 == 123", "456");
-		isTrue("column1 == 123", "123");
-		
-		isFalse("column1 != 123", "123");
-		isTrue("column1 != 123", "456");
-
-		isFalse("column1 < 123", "123");
-		isTrue("column1 < 123", "122");
-
-		isFalse("column1 > 123", "123");
-		isTrue("column1 > 123", "124");
-
-		isFalse("column1 <= 123", "124");
-		isTrue("column1 <= 123", "123");
-		isTrue("column1 <= 123", "122");
-
-		isFalse("column1 >= 123", "122");
-		isTrue("column1 >= 123", "123");
-		isTrue("column1 >= 123", "124");
-	}
-
-	@Test
-	public void compareString() throws InitializationException, ParseException {
-		isFalse("column1 == 'abc'", "abcd");
-		isTrue("column1 == 'abc'", "abc");
-		
-		isFalse("column1 != 'abc'", "abc");
-		isTrue("column1 != 'abc'", "asd");
-
-		isFalse("column1 < 'abc'", "abd");
-		isTrue("column1 < 'abc'", "abb");
-
-		isFalse("column1 > 'abc'", "abb");
-		isTrue("column1 > 'abc'", "abd");
-
-		isFalse("column1 <= 'abc'", "abd");
-		isTrue("column1 <= 'abc'", "abc");
-		isTrue("column1 <= 'abc'", "abb");
-
-		isFalse("column1 >= 'abc'", "abb");
-		isTrue("column1 >= 'abc'", "abc");
-		isTrue("column1 >= 'abc'", "abd");
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/core/parser/ReportLineTest.java b/services/billing-aws/src/test/java/com/epam/dlab/core/parser/ReportLineTest.java
deleted file mode 100644
index 72380a4..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/core/parser/ReportLineTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.core.parser;
-
-import com.epam.dlab.core.BillingUtils;
-import com.epam.dlab.exceptions.ParseException;
-import com.epam.dlab.model.aws.BillingResourceType;
-import com.epam.dlab.model.aws.ReportLine;
-import com.google.common.collect.Maps;
-import org.junit.Test;
-
-import static junit.framework.TestCase.assertEquals;
-
-public class ReportLineTest {
-
-	private void checkGetters(ReportLine r) {
-		assertEquals("dlabId", r.getDlabId());
-		assertEquals("user", r.getUser());
-		assertEquals("2016-01-22", r.getUsageDate());
-		assertEquals("Amazon Elastic Compute Cloud", r.getProduct());
-		assertEquals("usageType", r.getUsageType());
-		assertEquals(56.7, r.getUsage());
-		assertEquals(12.34, r.getCost());
-		assertEquals("USD", r.getCurrencyCode());
-		assertEquals("i-1234567890abcdefg", r.getResourceId());
-		assertEquals("value1", r.getTags().get("tag1"));
-		assertEquals("value2", r.getTags().get("tag2"));
-	}
-
-	@Test
-	public void set() throws ParseException {
-		ReportLine r = new ReportLine();
-
-		r.setDlabId("dlabId");
-		r.setCost(12.34);
-		r.setCurrencyCode("USD");
-		r.setProduct("Amazon Elastic Compute Cloud");
-		r.setResourceTypeId("i-1234567890abcdefg");
-		r.setUsage(56.7);
-		r.setUsageDate("2016-01-22");
-		r.setUsageType("usageType");
-		r.setUser("user");
-		r.setTags(Maps.newLinkedHashMap(BillingUtils.stringsToMap("tag1", "value1", "tag2", "value2")));
-
-		checkGetters(r);
-	}
-
-	private void checkResourceType(String product, String resourceTypeId,
-								   BillingResourceType expectedResourceType, String expectedResourceId) throws
-			ParseException {
-		ReportLine r = new ReportLine();
-		r.setProduct(product);
-		r.setResourceTypeId(resourceTypeId);
-
-		assertEquals(expectedResourceType, r.getResourceType());
-		assertEquals(expectedResourceId, r.getResourceId());
-	}
-
-	@Test
-	public void resourceType() throws ParseException {
-		checkResourceType("Amazon Elastic Compute Cloud", "i-000c0e51d117e3b4a", BillingResourceType.COMPUTER,
-				"i-000c0e51d117e3b4a");
-		checkResourceType("Amazon Elastic Compute Cloud", "vol-04c20f339836c56b6", BillingResourceType.STORAGE_EBS,
-				"vol-04c20f339836c56b6");
-		checkResourceType("Amazon Elastic Compute Cloud", "34.208.106.54", BillingResourceType.IP_ADDRESS,
-				"34.208.106.54");
-
-		checkResourceType("Amazon Elastic MapReduce",
-				"arn:aws:elasticmapreduce:us-west-2:203753054073:cluster/j-1FOBGFRC8X4XY", BillingResourceType
-						.CLUSTER, "j-1FOBGFRC8X4XY");
-
-		checkResourceType("Amazon Simple Storage Service", "dlab-s3", BillingResourceType.STORAGE_BUCKET, "dlab-s3");
-		checkResourceType("AmazonCloudWatch",
-				"arn:aws:logs:us-west-2:203753054073:log-group:CloudTrail/DefaultLogGroup", BillingResourceType.OTHER,
-				"arn:aws:logs:us-west-2:203753054073:log-group:CloudTrail/DefaultLogGroup");
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/logging/AppenderConsoleTest.java b/services/billing-aws/src/test/java/com/epam/dlab/logging/AppenderConsoleTest.java
deleted file mode 100644
index deae3f6..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/logging/AppenderConsoleTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.logging;
-
-import static junit.framework.TestCase.assertEquals;
-
-import org.junit.Test;
-
-public class AppenderConsoleTest {
-
-	@Test
-	public void config() {
-		AppenderConsole appender = new AppenderConsole();
-		assertEquals("console", appender.getType());
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/logging/AppenderFileTest.java b/services/billing-aws/src/test/java/com/epam/dlab/logging/AppenderFileTest.java
deleted file mode 100644
index f330771..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/logging/AppenderFileTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.logging;
-
-import static junit.framework.TestCase.assertEquals;
-
-import org.junit.Test;
-
-public class AppenderFileTest {
-
-	@Test
-	public void config() {
-		AppenderFile appender = new AppenderFile();
-		appender.setArchive(true);
-		appender.setArchivedFileCount(123);
-		appender.setArchivedLogFilenamePattern("file.log.zip");
-		appender.setCurrentLogFilename("file.log");
-		
-		assertEquals("file", appender.getType());
-		assertEquals(true, appender.getArchive());
-		assertEquals(123, appender.getArchivedFileCount());
-		assertEquals("file.log.zip", appender.getArchivedLogFilenamePattern());
-		assertEquals("file.log", appender.getCurrentLogFilename());
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/module/AdapterConsoleTest.java b/services/billing-aws/src/test/java/com/epam/dlab/module/AdapterConsoleTest.java
deleted file mode 100644
index 9df26c1..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/module/AdapterConsoleTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.module;
-
-import static junit.framework.TestCase.assertEquals;
-
-import org.junit.Test;
-
-public class AdapterConsoleTest {
-
-	@Test
-	public void config() {
-		AdapterConsole adapter = new AdapterConsole();
-		assertEquals(ModuleName.ADAPTER_CONSOLE, adapter.getType());
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/module/AdapterFileTest.java b/services/billing-aws/src/test/java/com/epam/dlab/module/AdapterFileTest.java
deleted file mode 100644
index 0894f30..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/module/AdapterFileTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.module;
-
-import static junit.framework.TestCase.assertEquals;
-
-import org.junit.Test;
-
-import com.epam.dlab.core.AdapterBase.Mode;
-
-public class AdapterFileTest {
-
-	@Test
-	public void config() {
-		AdapterFile adapter = new AdapterFile();
-		adapter.setMode(Mode.READ);
-		adapter.setWriteHeader(true);
-		adapter.setFile("filename");
-		
-		assertEquals(ModuleName.ADAPTER_FILE, adapter.getType());
-		assertEquals(Mode.READ, adapter.getMode());
-		assertEquals(true, adapter.isWriteHeader());
-		assertEquals("filename", adapter.getFile());
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/module/AdapterMongoDBTest.java b/services/billing-aws/src/test/java/com/epam/dlab/module/AdapterMongoDBTest.java
deleted file mode 100644
index 034c32c..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/module/AdapterMongoDBTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.module;
-
-import static junit.framework.TestCase.assertEquals;
-
-import org.junit.Test;
-
-import com.epam.dlab.core.AdapterBase.Mode;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.mongo.AdapterMongoDb;
-
-public class AdapterMongoDBTest {
-
-	@Test
-	public void config() throws InitializationException {
-		AdapterMongoDb adapter = new AdapterMongoDb();
-		adapter.setMode(Mode.WRITE);
-		adapter.setWriteHeader(false);
-		adapter.setHost("host");
-		adapter.setPort(123);
-		adapter.setDatabase("database");
-		adapter.setUsername("username");
-		adapter.setPassword("password");
-		adapter.setBufferSize(321);
-		adapter.setUpsert(true);
-		
-		assertEquals(ModuleName.ADAPTER_MONGO_DLAB, adapter.getType());
-		assertEquals(Mode.WRITE, adapter.getMode());
-		assertEquals(false, adapter.isWriteHeader());
-		assertEquals("host", adapter.getHost());
-		assertEquals(123, adapter.getPort());
-		assertEquals("database", adapter.getDatabase());
-		assertEquals("username", adapter.getUsername());
-		assertEquals("password", adapter.getPassword());
-		assertEquals(321, adapter.getBufferSize());
-		assertEquals(true, adapter.isUpsert());
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/module/ParserCsvTest.java b/services/billing-aws/src/test/java/com/epam/dlab/module/ParserCsvTest.java
deleted file mode 100644
index 63ec202..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/module/ParserCsvTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.module;
-
-import static junit.framework.TestCase.assertEquals;
-
-import java.util.List;
-
-import org.junit.Test;
-
-import com.epam.dlab.core.aggregate.AggregateGranularity;
-import com.epam.dlab.exceptions.InitializationException;
-import com.epam.dlab.exceptions.ParseException;
-import com.epam.dlab.module.aws.FilterAWS;
-import com.google.common.base.MoreObjects;
-import com.google.common.collect.Lists;
-
-public class ParserCsvTest {
-
-	@Test
-	public void config() throws InitializationException {
-		ParserCsv parser = new ParserCsv();
-		
-		parser.setFieldSeparator('a');
-		parser.setFieldTerminator('b');
-		parser.setEscapeChar('c');
-		parser.setDecimalSeparator('d');
-		parser.setGroupingSeparator('e');
-		parser.setAggregate(AggregateGranularity.DAY.toString());
-		parser.setColumnMapping("ColumnMapping");
-		parser.setHeaderLineNo(123);
-		parser.setSkipLines(321);
-
-		assertEquals(ModuleName.PARSER_CSV, parser.getType());
-		assertEquals('a', parser.getFieldSeparator());
-		assertEquals('b', parser.getFieldTerminator());
-		assertEquals('c', parser.getEscapeChar());
-		assertEquals('d', parser.getDecimalSeparator());
-		assertEquals('e', parser.getGroupingSeparator());
-		assertEquals(AggregateGranularity.DAY, parser.getAggregate());
-		assertEquals("ColumnMapping", parser.getColumnMapping());
-		assertEquals(123, parser.getHeaderLineNo());
-		assertEquals(321, parser.getSkipLines());
-
-		AdapterConsole adapterIn = new AdapterConsole();
-		AdapterConsole adapterOut = new AdapterConsole();
-		FilterAWS filter = new FilterAWS();
-		parser.build(adapterIn, adapterOut, filter);
-		
-		assertEquals(adapterIn, parser.getAdapterIn());
-		assertEquals(adapterOut, parser.getAdapterOut());
-		assertEquals(filter, parser.getFilter());
-		
-		parser.initialize();
-	}
-	
-	@Test
-	public void parseRow() throws ParseException {
-		ParserCsv parser = new ParserCsv();
-		final List<String> row = Lists.newArrayList("qwe", "rty", "\"uio\"", "asd\"fgh\"jkl");
-		final String line = "\"qwe\",\"rty\",\"\\\"uio\\\"\",\"asd\\\"fgh\\\"jkl\"";
-		List<String> rowParsed = parser.parseRow(line);
-		assertEquals(MoreObjects.toStringHelper(this).add("row", row).toString(), MoreObjects.toStringHelper(this).add("row", rowParsed).toString());
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/module/aws/AdapterS3FileTest.java b/services/billing-aws/src/test/java/com/epam/dlab/module/aws/AdapterS3FileTest.java
deleted file mode 100644
index 7d29792..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/module/aws/AdapterS3FileTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.module.aws;
-
-import static junit.framework.TestCase.assertEquals;
-
-import org.junit.Test;
-
-import com.epam.dlab.core.AdapterBase.Mode;
-import com.epam.dlab.module.ModuleName;
-
-public class AdapterS3FileTest {
-
-	@Test
-	public void config() {
-		AdapterS3File adapter = new AdapterS3File();
-		adapter.setMode(Mode.READ);
-		adapter.setWriteHeader(true);
-		adapter.setBucket("bucket");
-		adapter.setPath("path");
-		adapter.setAccountId("accountId");
-		adapter.setAccessKeyId("accessKeyId");
-		adapter.setSecretAccessKey("secretAccessKey");
-		
-		assertEquals(ModuleName.ADAPTER_S3_FILE, adapter.getType());
-		assertEquals(Mode.READ, adapter.getMode());
-		assertEquals(true, adapter.isWriteHeader());
-		assertEquals("bucket", adapter.getBucket());
-		assertEquals("path", adapter.getPath());
-		assertEquals("accountId", adapter.getAccountId());
-		assertEquals("accessKeyId", adapter.getAccessKeyId());
-		assertEquals("secretAccessKey", adapter.getSecretAccessKey());
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/module/aws/FilterAWSTest.java b/services/billing-aws/src/test/java/com/epam/dlab/module/aws/FilterAWSTest.java
deleted file mode 100644
index 03deeb9..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/module/aws/FilterAWSTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.module.aws;
-
-import com.epam.dlab.exceptions.ParseException;
-import com.epam.dlab.model.aws.ReportLine;
-import com.epam.dlab.module.ModuleName;
-import org.junit.Test;
-
-import static junit.framework.TestCase.assertEquals;
-
-public class FilterAWSTest {
-
-	@Test
-	public void config() {
-		FilterAWS filter = new FilterAWS();
-		filter.setCurrencyCode("currency");
-
-		assertEquals(ModuleName.FILTER_AWS, filter.getType());
-		assertEquals("currency", filter.getCurrencyCode());
-	}
-
-	@Test
-	public void canAccept() throws ParseException {
-		FilterAWS filter = new FilterAWS();
-		filter.setCurrencyCode("currency");
-
-		ReportLine row = new ReportLine();
-		row = filter.canAccept(row);
-
-		assertEquals(filter.getCurrencyCode(), row.getCurrencyCode());
-	}
-}
diff --git a/services/billing-aws/src/test/java/com/epam/dlab/module/aws/S3FileListTest.java b/services/billing-aws/src/test/java/com/epam/dlab/module/aws/S3FileListTest.java
deleted file mode 100644
index 56315b5..0000000
--- a/services/billing-aws/src/test/java/com/epam/dlab/module/aws/S3FileListTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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.module.aws;
-
-import com.amazonaws.services.s3.AmazonS3Client;
-import com.amazonaws.services.s3.model.ListObjectsV2Request;
-import com.amazonaws.services.s3.model.ListObjectsV2Result;
-import com.amazonaws.services.s3.model.S3ObjectSummary;
-import com.epam.dlab.core.ModuleData;
-import com.epam.dlab.exceptions.AdapterException;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.sql.Date;
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.TestCase.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class S3FileListTest {
-
-	@Test
-	public void sort() throws AdapterException {
-		final AmazonS3Client s3Client = mock(AmazonS3Client.class);
-		final ListObjectsV2Result result = mock(ListObjectsV2Result.class);
-		final ModuleData moduleData = mock(ModuleData.class);
-		final String[] array = {
-				"report-prefix/report/20160101-20160131/123456789/report-1.csv",
-				"report-prefix/report/20160101-20160131/123456789/report-2.csv",
-				"report-prefix/report/20160101-20160131/123456789/report-3.csv",
-				"report-prefix/report/20160202-20160231/123456789/report.csv",
-				"report-prefix/report/20160202-20160301/123456789/report.csv",
-				"report-prefix/report/20160303-20160301/123456789/report-1.csv",
-				"report-prefix/report/20160303-20160301/123456789/report-2.csv",
-				"report-prefix/report/20160303-20160302/123456789/report-1.csv",
-				"report-prefix/report/20160303-20160302/123456789/report-2.csv"
-		};
-		final List<S3ObjectSummary> objectSummaries = Arrays.asList(
-				getObjectSummary(array[0], LocalDate.of(2018, 4, 4)),
-				getObjectSummary(array[4], LocalDate.of(2018, 4, 4)),
-				getObjectSummary(array[1], LocalDate.of(2018, 4, 4)),
-				getObjectSummary(array[2], LocalDate.of(2018, 4, 4)),
-				getObjectSummary(array[3], LocalDate.of(2018, 4, 4)),
-				getObjectSummary(array[5], LocalDate.of(2018, 4, 4)),
-				getObjectSummary(array[6], LocalDate.of(2018, 4, 4)),
-				getObjectSummary(array[7], LocalDate.of(2018, 4, 4)),
-				getObjectSummary(array[8], LocalDate.of(2018, 4, 4))
-
-		);
-		when(s3Client.listObjectsV2(any(ListObjectsV2Request.class))).thenReturn(result);
-		when(result.getObjectSummaries()).thenReturn(objectSummaries);
-		when(moduleData.wasProcessed(any(),any(), anyString())).thenReturn(false);
-
-		S3FileList s3list = new S3FileList(false, "test", moduleData);
-		final List<String> list = s3list.getFiles(s3Client);
-
-		assertEquals(array.length, list.size());
-		for (int i = 0; i < array.length; i++) {
-			assertEquals(array[i], list.get(i));
-		}
-	}
-
-	@Test
-	public void testGettingLastFilesInBillingPeriod() throws Exception {
-		final ListObjectsV2Result result = mock(ListObjectsV2Result.class);
-		final ModuleData moduleData = mock(ModuleData.class);
-		final List<S3ObjectSummary> objectSummaries = Arrays.asList(
-				getObjectSummary("DLAB-billing/reportName/20180101-20180201/guid1/test-1.csv.zip",
-						LocalDate.of(2018, 4, 1)),
-				getObjectSummary("DLAB-billing/reportName/20180101-20180201/guid1/test-2.csv.zip",
-						LocalDate.of(2018, 4, 1)),
-				getObjectSummary("DLAB-billing/reportName/20180101-20180201/guid0/test-1.csv.zip",
-						LocalDate.of(2018, 1, 1)),
-				getObjectSummary("DLAB-billing/reportName/20180201-20180301/guid0/test-1.csv.zip",
-						LocalDate.of(2018, 1, 1)),
-				getObjectSummary("DLAB-billing/reportName/20180202-20180301/guid0/test-2.csv.zip",
-						LocalDate.of(2018, 1, 1))
-
-		);
-		when(result.getObjectSummaries()).thenReturn(objectSummaries);
-		final List<String> files = new S3FileList(true, null, moduleData).lastFilesPerBillingPeriod(result
-				.getObjectSummaries());
-
-		assertEquals(4, files.size());
-		assertTrue(files.contains("DLAB-billing/reportName/20180101-20180201/guid1/test-1.csv.zip"));
-		assertTrue(files.contains("DLAB-billing/reportName/20180101-20180201/guid1/test-2.csv.zip"));
-		assertTrue(files.contains("DLAB-billing/reportName/20180201-20180301/guid0/test-1.csv.zip"));
-		assertTrue(files.contains("DLAB-billing/reportName/20180202-20180301/guid0/test-2.csv.zip"));
-
-
-	}
-
-	private S3ObjectSummary getObjectSummary(String key, LocalDate modificationDate) {
-		final S3ObjectSummary objectSummary = new S3ObjectSummary();
-		objectSummary.setKey(key);
-		objectSummary.setLastModified(Date.from(modificationDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
-		return objectSummary;
-	}
-}
diff --git a/services/billing-azure/billing.yml b/services/billing-azure/billing.yml
index 5361d90..188bbe6 100644
--- a/services/billing-azure/billing.yml
+++ b/services/billing-azure/billing.yml
@@ -26,7 +26,7 @@
     mongodb:
       username: admin
       password: MONGO_PASSWORD
-      database: dlabdb
+      database: datalabdb
       port: MONGO_PORT
       host: MONGO_HOST
 
@@ -41,20 +41,20 @@
 server.ssl.key-alias: ssn
 
 logging:
-  file: /var/opt/dlab/log/ssn/billing.log
+  file: /var/opt/datalab/log/ssn/billing.log
   level:
     com:
       epam: trace
 
 keycloak:
   bearer-only: true
-  realm: dlab
+  realm: datalab
   resource: KEYCLOAK_CLIENT_ID
   credentials.secret: KEYCLOAK_CLIENT_SECRET
   ssl-required: none
   auth-server-url: KEYCLOAK_AUTH_SERVER_URL
 
-dlab:
+datalab:
   sbn: SERVICE_BASE_NAME
   billingEnabled: true
 
@@ -86,7 +86,7 @@
     port: MONGO_PORT
     username: admin
     password: MONGO_PASSWORD
-    database: dlabdb
+    database: datalabdb
   ssnStorageAccountTagName: <AZURE_SSN_STORAGE_ACCOUNT_TAG>
   sharedStorageAccountTagName: <AZURE_SHARED_STORAGE_ACCOUNT_TAG>
   datalakeTagName: <AZURE_DATALAKE_TAG>
\ No newline at end of file
diff --git a/services/billing-azure/pom.xml b/services/billing-azure/pom.xml
index 75c8e35..340157a 100644
--- a/services/billing-azure/pom.xml
+++ b/services/billing-azure/pom.xml
@@ -22,8 +22,8 @@
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <parent>
-        <artifactId>dlab</artifactId>
-        <groupId>com.epam.dlab</groupId>
+        <artifactId>datalab</artifactId>
+        <groupId>com.epam.datalab</groupId>
         <version>1.0</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
@@ -88,8 +88,8 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>dlab-model</artifactId>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>datalab-model</artifactId>
             <version>${project.parent.version}</version>
         </dependency>
 
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/AzureInvoiceCalculationService.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/AzureInvoiceCalculationService.java
new file mode 100644
index 0000000..6601ec3
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/AzureInvoiceCalculationService.java
@@ -0,0 +1,242 @@
+/*
+ * 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.datalab.billing.azure;
+
+import com.epam.datalab.billing.BillingCalculationUtils;
+import com.epam.datalab.billing.azure.config.BillingConfigurationAzure;
+import com.epam.datalab.billing.azure.model.AzureDailyResourceInvoice;
+import com.epam.datalab.billing.azure.rate.AzureRateCardClient;
+import com.epam.datalab.billing.azure.rate.Meter;
+import com.epam.datalab.billing.azure.rate.RateCardResponse;
+import com.epam.datalab.billing.azure.usage.AzureUsageAggregateClient;
+import com.epam.datalab.billing.azure.usage.UsageAggregateRecord;
+import com.epam.datalab.billing.azure.usage.UsageAggregateResponse;
+import com.epam.datalab.exceptions.DatalabException;
+import com.microsoft.azure.AzureEnvironment;
+import com.microsoft.azure.credentials.ApplicationTokenCredentials;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Filters billing data and calculate prices for each
+ * resource using combination of Microsoft Azure RateCard API and Usage API
+ */
+@Slf4j
+public class AzureInvoiceCalculationService {
+
+    /**
+     * According to Microsoft Azure documentation
+     * https://docs.microsoft.com/en-us/azure/active-directory/active-directory-configurable-token-lifetimes
+     * min TTL time of token 10 minutes
+     */
+    private static final long MAX_AUTH_TOKEN_TTL_MILLIS = 9L * 60L * 1000L;
+
+    private BillingConfigurationAzure billingConfigurationAzure;
+
+    /**
+     * Constructs service class
+     *
+     * @param billingConfigurationAzure contains <code>billing-azure</code> module configuration
+     */
+    public AzureInvoiceCalculationService(BillingConfigurationAzure billingConfigurationAzure) {
+        this.billingConfigurationAzure = billingConfigurationAzure;
+    }
+
+    /**
+     * Prepares invoice records aggregated by day
+     *
+     * @param from start usage period
+     * @param to   end usage period
+     * @return list of invoice records for each meter category aggregated by day
+     */
+    public List<AzureDailyResourceInvoice> generateInvoiceData(String from, String to) {
+
+        long refreshTokenTime = System.currentTimeMillis() + MAX_AUTH_TOKEN_TTL_MILLIS;
+
+        String authenticationToken = getNewToken();
+        AzureRateCardClient azureRateCardClient = new AzureRateCardClient(billingConfigurationAzure,
+                authenticationToken);
+        AzureUsageAggregateClient azureUsageAggregateClient = new AzureUsageAggregateClient(billingConfigurationAzure,
+                authenticationToken);
+
+        List<AzureDailyResourceInvoice> invoiceData = new ArrayList<>();
+
+        try {
+
+            UsageAggregateResponse usageAggregateResponse = null;
+            Map<String, Meter> rates = transformRates(azureRateCardClient.getRateCard());
+
+            do {
+
+                if (usageAggregateResponse != null && StringUtils.isNotEmpty(usageAggregateResponse.getNextLink())) {
+                    log.info("Get usage of resources using link {}", usageAggregateResponse.getNextLink());
+                    usageAggregateResponse = azureUsageAggregateClient.getUsageAggregateResponse
+                            (usageAggregateResponse.getNextLink());
+                    log.info("Received usage of resources. Items {} ", usageAggregateResponse.getValue() != null ?
+                            usageAggregateResponse.getValue().size() : 0);
+                    log.info("Next link is {}", usageAggregateResponse.getNextLink());
+                } else if (usageAggregateResponse == null) {
+                    log.info("Get usage of resources from {} to {}", from, to);
+                    usageAggregateResponse = azureUsageAggregateClient.getUsageAggregateResponse(from, to);
+                    log.info("Received usage of resources. Items {} ", usageAggregateResponse.getValue() != null ?
+                            usageAggregateResponse.getValue().size() : 0);
+                    log.info("Next link is {}", usageAggregateResponse.getNextLink());
+                }
+
+                invoiceData.addAll(generateBillingInfo(rates, usageAggregateResponse));
+
+                if (System.currentTimeMillis() > refreshTokenTime) {
+                    authenticationToken = getNewToken();
+                    azureUsageAggregateClient.setAuthToken(authenticationToken);
+                }
+
+            } while (StringUtils.isNotEmpty(usageAggregateResponse.getNextLink()));
+
+        } catch (IOException | RuntimeException | URISyntaxException e) {
+            log.error("Cannot calculate billing information", e);
+            throw new DatalabException("Cannot prepare invoice data", e);
+        }
+
+        return invoiceData;
+    }
+
+    private List<AzureDailyResourceInvoice> generateBillingInfo(Map<String, Meter> rates, UsageAggregateResponse
+            usageAggregateResponse) {
+        List<UsageAggregateRecord> usageAggregateRecordList = usageAggregateResponse.getValue();
+        List<AzureDailyResourceInvoice> invoices = new ArrayList<>();
+
+        if (usageAggregateRecordList != null && !usageAggregateRecordList.isEmpty()) {
+            log.info("Processing {} usage records", usageAggregateRecordList.size());
+            usageAggregateRecordList = usageAggregateRecordList.stream().filter(e ->
+                    matchProperStructure(e) && isBillableDatalabResource(e))
+                    .collect(Collectors.toList());
+
+            log.info("Applicable records number is {}", usageAggregateRecordList.size());
+
+            for (UsageAggregateRecord record : usageAggregateRecordList) {
+                invoices.add(calculateInvoice(rates, record, record.getProperties().getParsedInstanceData()
+                        .getMicrosoftResources().getTags().get("Name")));
+            }
+        } else {
+            log.error("No usage records in response.");
+        }
+
+        return invoices;
+    }
+
+    private Map<String, Meter> transformRates(RateCardResponse rateCardResponse) {
+        Map<String, Meter> rates = new HashMap<>();
+        for (Meter meter : rateCardResponse.getMeters()) {
+            rates.put(meter.getMeterId(), meter);
+        }
+
+        return rates;
+    }
+
+    private boolean matchProperStructure(UsageAggregateRecord record) {
+        if (record.getProperties() == null) {
+            return false;
+        }
+
+        if (record.getProperties().getMeterId() == null || record.getProperties().getMeterId().isEmpty()) {
+            return false;
+        }
+
+        return !(record.getProperties().getParsedInstanceData() == null
+                || record.getProperties().getParsedInstanceData().getMicrosoftResources() == null
+                || record.getProperties().getParsedInstanceData().getMicrosoftResources().getTags() == null
+                || record.getProperties().getParsedInstanceData().getMicrosoftResources().getTags().isEmpty());
+    }
+
+    private boolean isBillableDatalabResource(UsageAggregateRecord record) {
+        String datalabId = record.getProperties().getParsedInstanceData().getMicrosoftResources().getTags().get("Name");
+        return datalabId != null && !datalabId.isEmpty() && datalabId.startsWith(billingConfigurationAzure.getSbn());
+    }
+
+    private AzureDailyResourceInvoice calculateInvoice(Map<String, Meter> rates, UsageAggregateRecord record, String datalabId) {
+        String meterId = record.getProperties().getMeterId();
+        Meter rateCard = rates.get(meterId);
+
+        if (rateCard != null) {
+            Map<String, Double> meterRates = rateCard.getMeterRates();
+            if (meterRates != null) {
+                Double rate = meterRates.get(AzureRateCardClient.MAIN_RATE_KEY);
+                if (rate != null) {
+                    return AzureDailyResourceInvoice.builder()
+                            .datalabId(datalabId)
+                            .usageStartDate(getDay(record.getProperties().getUsageStartTime()))
+                            .usageEndDate(getDay(record.getProperties().getUsageEndTime()))
+                            .meterCategory(record.getProperties().getMeterCategory())
+                            .cost(BillingCalculationUtils.round(rate * record.getProperties().getQuantity(), 3))
+                            .day(getDay(record.getProperties().getUsageStartTime()))
+                            .currencyCode(billingConfigurationAzure.getCurrency())
+                            .build();
+                } else {
+                    log.error("Rate Card {} has no rate for meter id {} and rate id {}. Skip record {}.",
+                            rateCard, meterId, AzureRateCardClient.MAIN_RATE_KEY, record);
+                }
+            } else {
+                log.error("Rate Card {} has no meter rates fro meter id {}. Skip record {}",
+                        rateCard, meterId, record);
+            }
+        } else {
+            log.error("Meter rate {} form usage aggregate is not found in rate card. Skip record {}.", meterId, record);
+        }
+
+        return null;
+    }
+
+    private String getNewToken() {
+        try {
+            log.info("Requesting authentication token ... ");
+            ApplicationTokenCredentials applicationTokenCredentials = new ApplicationTokenCredentials(
+                    billingConfigurationAzure.getClientId(),
+                    billingConfigurationAzure.getTenantId(),
+                    billingConfigurationAzure.getClientSecret(),
+                    AzureEnvironment.AZURE);
+
+            return applicationTokenCredentials.getToken(AzureEnvironment.AZURE.resourceManagerEndpoint());
+        } catch (IOException e) {
+            log.error("Cannot retrieve authentication token due to", e);
+            throw new DatalabException("Cannot retrieve authentication token", e);
+        }
+    }
+
+    private String getDay(String dateTime) {
+        if (dateTime != null) {
+            String[] parts = dateTime.split("T");
+            if (parts.length == 2) {
+                return parts[0];
+            }
+        }
+
+        log.error("Wrong usage date format {} ", dateTime);
+        return null;
+    }
+
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/BillingAzureApplication.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/BillingAzureApplication.java
new file mode 100644
index 0000000..5d10d9e
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/BillingAzureApplication.java
@@ -0,0 +1,36 @@
+/*
+ * 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.datalab.billing.azure;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+
+@SpringBootApplication
+@EnableMongoRepositories
+@EnableConfigurationProperties
+public class BillingAzureApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(BillingAzureApplication.class, args);
+    }
+
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/CalculateBillingService.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/CalculateBillingService.java
new file mode 100644
index 0000000..4de0dba
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/CalculateBillingService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab.billing.azure;
+
+import com.epam.datalab.dto.billing.BillingData;
+
+import java.util.List;
+
+@FunctionalInterface
+public interface CalculateBillingService {
+    List<BillingData> getBillingData();
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/CalculateBillingServiceImpl.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/CalculateBillingServiceImpl.java
new file mode 100644
index 0000000..7a89c83
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/CalculateBillingServiceImpl.java
@@ -0,0 +1,245 @@
+/*
+ * 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.datalab.billing.azure;
+
+import com.epam.datalab.MongoKeyWords;
+import com.epam.datalab.billing.azure.config.BillingConfigurationAzure;
+import com.epam.datalab.billing.azure.model.AzureDailyResourceInvoice;
+import com.epam.datalab.billing.azure.model.BillingPeriod;
+import com.epam.datalab.dto.billing.BillingData;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.model.azure.AzureAuthFile;
+import com.epam.datalab.util.mongo.modules.IsoDateModule;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.mongodb.BasicDBObject;
+import com.mongodb.client.model.Filters;
+import com.mongodb.client.model.UpdateOptions;
+import com.mongodb.client.result.UpdateResult;
+import lombok.extern.slf4j.Slf4j;
+import org.bson.Document;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDate;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class CalculateBillingServiceImpl implements CalculateBillingService {
+    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z");
+    private static final String SCHEDULER_ID = "azureBillingScheduler";
+    private final BillingConfigurationAzure billingConfigurationAzure;
+    private final MongoDbBillingClient mongoDbBillingClient;
+    private ObjectMapper objectMapper;
+
+    @Autowired
+    public CalculateBillingServiceImpl(BillingConfigurationAzure configuration) throws IOException {
+        billingConfigurationAzure = configuration;
+        objectMapper = new ObjectMapper().registerModule(new IsoDateModule());
+        Path path = Paths.get(billingConfigurationAzure.getAuthenticationFile());
+
+        if (path.toFile().exists()) {
+            log.info("Read and override configs using auth file");
+            try {
+                AzureAuthFile azureAuthFile = new ObjectMapper().readValue(path.toFile(), AzureAuthFile.class);
+                this.billingConfigurationAzure.setClientId(azureAuthFile.getClientId());
+                this.billingConfigurationAzure.setClientSecret(azureAuthFile.getClientSecret());
+                this.billingConfigurationAzure.setTenantId(azureAuthFile.getTenantId());
+                this.billingConfigurationAzure.setSubscriptionId(azureAuthFile.getSubscriptionId());
+            } catch (IOException e) {
+                log.error("Cannot read configuration file", e);
+                throw e;
+            }
+            log.info("Configs from auth file are used");
+        } else {
+            log.info("Configs from yml file are used");
+        }
+
+        this.mongoDbBillingClient = new MongoDbBillingClient
+                (billingConfigurationAzure.getAggregationOutputMongoDataSource().getHost(),
+                        billingConfigurationAzure.getAggregationOutputMongoDataSource().getPort(),
+                        billingConfigurationAzure.getAggregationOutputMongoDataSource().getDatabase(),
+                        billingConfigurationAzure.getAggregationOutputMongoDataSource().getUsername(),
+                        billingConfigurationAzure.getAggregationOutputMongoDataSource().getPassword());
+    }
+
+    @Override
+    public List<BillingData> getBillingData() {
+        try {
+            BillingPeriod billingPeriod = getBillingPeriod();
+            DateTime currentTime = new DateTime().withZone(DateTimeZone.UTC);
+            if (billingPeriod == null) {
+                saveBillingPeriod(initialSchedulerInfo(currentTime));
+            } else {
+                log.info("Billing period from db is {}", billingPeriod);
+
+                if (shouldTriggerJobByTime(currentTime, billingPeriod)) {
+                    List<BillingData> billingData = getBillingData(billingPeriod);
+                    boolean hasNew = !billingData.isEmpty();
+                    updateBillingPeriod(billingPeriod, currentTime, hasNew);
+                    return billingData;
+                }
+            }
+        } catch (RuntimeException e) {
+            log.error("Cannot update billing information", e);
+        }
+        return Collections.emptyList();
+    }
+
+    private BillingPeriod initialSchedulerInfo(DateTime currentTime) {
+
+        BillingPeriod initialBillingPeriod = new BillingPeriod();
+        initialBillingPeriod.setFrom(currentTime.minusDays(2).toDateMidnight().toDate());
+        initialBillingPeriod.setTo(currentTime.toDateMidnight().toDate());
+
+        log.info("Initial scheduler info {}", initialBillingPeriod);
+
+        return initialBillingPeriod;
+
+    }
+
+    private boolean shouldTriggerJobByTime(DateTime currentTime, BillingPeriod billingPeriod) {
+
+        DateTime dateTimeToFromBillingPeriod = new DateTime(billingPeriod.getTo()).withZone(DateTimeZone.UTC);
+
+        log.info("Comparing current time[{}, {}] and from scheduler info [{}, {}]", currentTime,
+                currentTime.toDateMidnight(),
+                dateTimeToFromBillingPeriod, dateTimeToFromBillingPeriod.toDateMidnight());
+
+        if (currentTime.toDateMidnight().isAfter(dateTimeToFromBillingPeriod.toDateMidnight())
+                || currentTime.toDateMidnight().isEqual(dateTimeToFromBillingPeriod.toDateMidnight())) {
+            log.info("Should trigger the job by time");
+            return true;
+        }
+
+        log.info("Should not trigger the job by time");
+        return false;
+    }
+
+    private List<BillingData> getBillingData(BillingPeriod billingPeriod) {
+        AzureInvoiceCalculationService azureInvoiceCalculationService
+                = new AzureInvoiceCalculationService(billingConfigurationAzure);
+
+        List<AzureDailyResourceInvoice> dailyInvoices = azureInvoiceCalculationService.generateInvoiceData(
+                DATE_TIME_FORMATTER.print(new DateTime(billingPeriod.getFrom()).withZone(DateTimeZone.UTC)),
+                DATE_TIME_FORMATTER.print(new DateTime(billingPeriod.getTo()).withZone(DateTimeZone.UTC)));
+
+        if (!dailyInvoices.isEmpty()) {
+            return dailyInvoices
+                    .stream()
+                    .map(this::toBillingData)
+                    .collect(Collectors.toList());
+        } else {
+            log.warn("Daily invoices is empty for period {}", billingPeriod);
+            return Collections.emptyList();
+        }
+    }
+
+    private void updateBillingPeriod(BillingPeriod billingPeriod, DateTime currentTime, boolean updates) {
+
+        try {
+            mongoDbBillingClient.getDatabase().getCollection(MongoKeyWords.AZURE_BILLING_SCHEDULER_HISTORY).insertOne(
+                    Document.parse(objectMapper.writeValueAsString(billingPeriod)).append("updates", updates));
+            log.debug("History of billing periods is updated with {}",
+                    objectMapper.writeValueAsString(billingPeriod));
+        } catch (JsonProcessingException e) {
+            log.error("Cannot update history of billing periods", e);
+
+        }
+
+        billingPeriod.setFrom(billingPeriod.getTo());
+
+        if (new DateTime(billingPeriod.getFrom()).withZone(DateTimeZone.UTC).toDateMidnight()
+                .isEqual(currentTime.toDateMidnight())) {
+
+            log.info("Setting billing to one day later");
+            billingPeriod.setTo(currentTime.plusDays(1).toDateMidnight().toDate());
+
+        } else {
+            billingPeriod.setTo(currentTime.toDateMidnight().toDate());
+        }
+
+        saveBillingPeriod(billingPeriod);
+    }
+
+    private boolean saveBillingPeriod(BillingPeriod billingPeriod) {
+        log.debug("Saving billing period {}", billingPeriod);
+
+        try {
+            UpdateResult updateResult = mongoDbBillingClient.getDatabase().getCollection(MongoKeyWords.AZURE_BILLING_SCHEDULER)
+                    .updateMany(Filters.eq(MongoKeyWords.MONGO_ID, SCHEDULER_ID),
+                            new BasicDBObject("$set",
+                                    Document.parse(objectMapper.writeValueAsString(billingPeriod))
+                                            .append(MongoKeyWords.MONGO_ID, SCHEDULER_ID))
+                            , new UpdateOptions().upsert(true)
+                    );
+
+            log.debug("Billing period save operation result is {}", updateResult);
+            return true;
+        } catch (JsonProcessingException e) {
+            log.error("Cannot save billing period", e);
+        }
+
+        return false;
+    }
+
+    private BillingPeriod getBillingPeriod() {
+        log.debug("Get billing period");
+
+        try {
+            Document document = mongoDbBillingClient.getDatabase().getCollection(MongoKeyWords.AZURE_BILLING_SCHEDULER)
+                    .find(Filters.eq(MongoKeyWords.MONGO_ID, SCHEDULER_ID)).first();
+
+            log.debug("Retrieved billing period document {}", document);
+            if (document != null) {
+                return objectMapper.readValue(document.toJson(), BillingPeriod.class);
+            }
+
+            return null;
+
+        } catch (IOException e) {
+            log.error("Cannot save billing period", e);
+            throw new DatalabException("Cannot parse string", e);
+        }
+    }
+
+    private BillingData toBillingData(AzureDailyResourceInvoice billingData) {
+        return BillingData.builder()
+                .tag(billingData.getDatalabId().toLowerCase())
+                .usageDateFrom(Optional.ofNullable(billingData.getUsageStartDate()).map(LocalDate::parse).orElse(null))
+                .usageDateTo(Optional.ofNullable(billingData.getUsageEndDate()).map(LocalDate::parse).orElse(null))
+                .usageDate(billingData.getDay())
+                .product(billingData.getMeterCategory())
+                .cost(billingData.getCost())
+                .currency(billingData.getCurrencyCode())
+                .build();
+    }
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/MongoDbBillingClient.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/MongoDbBillingClient.java
new file mode 100644
index 0000000..b0e7929
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/MongoDbBillingClient.java
@@ -0,0 +1,50 @@
+/*
+ * 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.datalab.billing.azure;
+
+import com.google.common.collect.Lists;
+import com.mongodb.MongoClient;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
+import com.mongodb.client.MongoDatabase;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class MongoDbBillingClient {
+
+    private MongoClient client;
+    private MongoDatabase database;
+
+    public MongoDbBillingClient(String host, int port, String databaseName, String username, String password) {
+        this.client = new MongoClient(new ServerAddress(host, port),
+                Lists.newArrayList(MongoCredential.createCredential(username,
+                        databaseName, password.toCharArray())));
+
+        this.database = client.getDatabase(databaseName);
+    }
+
+    public MongoClient getClient() {
+        return client;
+    }
+
+    public MongoDatabase getDatabase() {
+        return database;
+    }
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/MongoDocument.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/MongoDocument.java
new file mode 100644
index 0000000..60ee4ca
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/MongoDocument.java
@@ -0,0 +1,70 @@
+/*
+ * 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.datalab.billing.azure;
+
+import com.epam.datalab.exceptions.DatalabException;
+import org.bson.Document;
+
+import java.lang.reflect.Field;
+
+public abstract class MongoDocument<T> {
+
+    protected Document to() {
+        Field[] fields = this.getClass().getDeclaredFields();
+        Document document = new Document();
+
+        try {
+            for (Field field : fields) {
+                field.setAccessible(true);
+                if (field.getType().isEnum()) {
+                    document.append(field.getName(), field.get(this).toString());
+                } else {
+                    document.append(field.getName(), field.get(this));
+                }
+            }
+
+            return document;
+
+        } catch (IllegalArgumentException | IllegalAccessException e) {
+            throw new DatalabException("", e);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private T from(Document document) {
+
+        Field[] fields = this.getClass().getDeclaredFields();
+
+        try {
+            for (Field field : fields) {
+                field.setAccessible(true);
+
+                if (field.getType().isEnum()) {
+                    field.set(this, Enum.valueOf((Class<Enum>) field.getType(), (String) document.get(field.getName())));
+                } else {
+                    field.set(this, document.get(field.getName()));
+                }
+            }
+            return (T) this;
+        } catch (IllegalArgumentException | IllegalAccessException e) {
+            throw new DatalabException("", e);
+        }
+    }
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/config/AggregationOutputMongoDataSource.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/config/AggregationOutputMongoDataSource.java
new file mode 100644
index 0000000..9828bea
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/config/AggregationOutputMongoDataSource.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.datalab.billing.azure.config;
+
+import lombok.Data;
+
+@Data
+public class AggregationOutputMongoDataSource {
+    private String host;
+    private int port;
+    private String username;
+    private String password;
+    private String database;
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/config/BillingConfigurationAzure.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/config/BillingConfigurationAzure.java
new file mode 100644
index 0000000..b35e5ab
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/config/BillingConfigurationAzure.java
@@ -0,0 +1,52 @@
+/*
+ * 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.datalab.billing.azure.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties("datalab")
+@Data
+public class BillingConfigurationAzure {
+    private String sbn;
+    private long initialDelay;
+    private long period;
+
+    private String clientId;
+    private String clientSecret;
+    private String tenantId;
+    private String subscriptionId;
+
+    private String authenticationFile;
+
+    private String offerNumber;
+    private String currency;
+    private String locale;
+    private String regionInfo;
+    private boolean billingEnabled;
+
+    private String ssnStorageAccountTagName;
+    private String sharedStorageAccountTagName;
+    private String datalakeTagName;
+
+    private AggregationOutputMongoDataSource aggregationOutputMongoDataSource;
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/config/LoggingConfigurationFactory.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/config/LoggingConfigurationFactory.java
new file mode 100644
index 0000000..8bff0da
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/config/LoggingConfigurationFactory.java
@@ -0,0 +1,166 @@
+/*
+ * 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.datalab.billing.azure.config;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import com.epam.datalab.billing.azure.logging.AppenderBase;
+import com.epam.datalab.exceptions.InitializationException;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Configuration and factory for logging.
+ */
+public class LoggingConfigurationFactory {
+
+    /**
+     * Default logging level for all appenders.
+     */
+    @JsonProperty
+    private Level level = Level.INFO;
+
+    /**
+     * List of logging levels for appenders.
+     */
+    @JsonIgnore
+    private ImmutableMap<String, Level> loggers = ImmutableMap.of();
+
+    /**
+     * List of logging appenders.
+     */
+    @JsonProperty
+    private ImmutableList<AppenderBase> appenders = ImmutableList.of();
+
+
+    /**
+     * Return the default logging level for all appenders.
+     */
+    public Level getLevel() {
+        return level;
+    }
+
+    /**
+     * Set the default logging level for all appenders.
+     */
+    public void setLevel(String level) throws InitializationException {
+        this.level = toLevel(level);
+    }
+
+    /**
+     * Return the list of logging levels for appenders.
+     */
+    public ImmutableMap<String, Level> getLoggers() {
+        return loggers;
+    }
+
+    /**
+     * Set the list of logging levels for appenders.
+     */
+    @JsonProperty
+    public void setLoggers(ImmutableMap<String, JsonNode> loggers) throws InitializationException {
+        ImmutableMap.Builder<String, Level> levels = new ImmutableMap.Builder<>();
+        for (String key : loggers.keySet()) {
+            JsonNode node = loggers.get(key);
+            levels.put(key, toLevel(node.asText()));
+        }
+        this.loggers = levels.build();
+    }
+
+    /**
+     * Return the list of logging appenders.
+     */
+    public ImmutableList<AppenderBase> getAppenders() {
+        return appenders;
+    }
+
+    /**
+     * Set the list of logging appenders.
+     */
+    public void setAppenders(ImmutableList<AppenderBase> appenders) {
+        this.appenders = appenders;
+    }
+
+
+    /**
+     * Translate the name of logging level to {@link Level}.
+     *
+     * @param level the name of logging level.
+     * @return logging level.
+     * @throws InitializationException if given unknown logging level name.
+     */
+    private Level toLevel(String level) throws InitializationException {
+        Level l = Level.toLevel(level, null);
+        if (l == null) {
+            throw new InitializationException("Unknown logging level: " + level);
+        }
+        return l;
+    }
+
+    /**
+     * Configure logging appenders.
+     *
+     * @throws InitializationException
+     */
+    public void configure() throws InitializationException {
+        if (appenders == null) {
+            throw new InitializationException("Configuration property logging.appenders cannot be null.");
+        }
+        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+        context.reset();
+
+        for (AppenderBase appender : appenders) {
+            appender.configure(context);
+        }
+
+        Logger logger = context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
+        logger.setLevel(level);
+        for (String name : loggers.keySet()) {
+            logger = context.getLogger(name);
+            logger.setLevel(loggers.get(name));
+        }
+    }
+
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @param self the object to generate the string for (typically this), used only for its class name.
+     */
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("level", level)
+                .add("loggers", loggers)
+                .add("appenders", appenders);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .toString();
+    }
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/config/SecurityConfig.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/config/SecurityConfig.java
new file mode 100644
index 0000000..836b3b6
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/config/SecurityConfig.java
@@ -0,0 +1,66 @@
+/*
+ * 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.datalab.billing.azure.config;
+
+import org.keycloak.adapters.KeycloakConfigResolver;
+import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
+import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
+import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
+import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
+import org.springframework.security.core.session.SessionRegistryImpl;
+import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
+import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
+
+@KeycloakConfiguration
+class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
+
+    @Autowired
+    public void configureGlobal(AuthenticationManagerBuilder auth) {
+        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
+        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
+        auth.authenticationProvider(keycloakAuthenticationProvider);
+    }
+
+    @Bean
+    public KeycloakConfigResolver keycloakConfigResolver() {
+        return new KeycloakSpringBootConfigResolver();
+    }
+
+    @Bean
+    @Override
+    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
+        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
+    }
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        super.configure(http);
+        http
+                .anonymous().disable()
+                .authorizeRequests()
+                .anyRequest()
+                .authenticated();
+    }
+}
\ No newline at end of file
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/controller/BillingController.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/controller/BillingController.java
new file mode 100644
index 0000000..5536208
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/controller/BillingController.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.billing.azure.controller;
+
+import com.epam.datalab.billing.azure.CalculateBillingService;
+import com.epam.datalab.dto.billing.BillingData;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+public class BillingController {
+
+    private final CalculateBillingService billingService;
+
+    public BillingController(CalculateBillingService billingService) {
+        this.billingService = billingService;
+    }
+
+    @GetMapping
+    public ResponseEntity<List<BillingData>> getBilling() {
+        return new ResponseEntity<>(billingService.getBillingData(), HttpStatus.OK);
+    }
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/logging/AppenderBase.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/logging/AppenderBase.java
new file mode 100644
index 0000000..7350414
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/logging/AppenderBase.java
@@ -0,0 +1,103 @@
+/*
+ * 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.datalab.billing.azure.logging;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.OutputStreamAppender;
+import com.epam.datalab.exceptions.InitializationException;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.TimeZone;
+
+/**
+ * Abstract class provides base configuration for the log appenders.
+ */
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
+public abstract class AppenderBase {
+
+    /**
+     * Log format pattern.
+     */
+    private final String logFormatPattern = "%-5p [%d{ISO8601," + TimeZone.getDefault().getID() + "}] %c: %m%n%rEx";
+
+    /**
+     * Perform configure of appender.
+     *
+     * @param context the context of logger.
+     */
+    public abstract void configure(LoggerContext context) throws InitializationException;
+
+    /**
+     * Perform the base configure of appender.
+     *
+     * @param context      the context of logger.
+     * @param appenderName the name of appender.
+     * @param appender     the class instance of appender.
+     */
+    public void configure(LoggerContext context, String appenderName, OutputStreamAppender<ILoggingEvent> appender) {
+        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
+        encoder.setPattern(logFormatPattern);
+        encoder.setContext(context);
+        encoder.start();
+
+        appender.setContext(context);
+        appender.setName(appenderName);
+        appender.setEncoder(encoder);
+        appender.start();
+
+        Logger logger = context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
+        logger.addAppender(appender);
+        logger.setAdditive(true);
+    }
+
+    /**
+     * Return the name of type for appender.
+     */
+    @JsonIgnore
+    public String getType() {
+        Class<? extends AppenderBase> clazz = this.getClass();
+        return (clazz.isAnnotationPresent(JsonTypeName.class) ?
+                clazz.getAnnotation(JsonTypeName.class).value() : clazz.getName());
+    }
+
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @param self the object to generate the string for (typically this), used only for its class name.
+     */
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("type", getType());
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .toString();
+    }
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/logging/AppenderConsole.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/logging/AppenderConsole.java
new file mode 100644
index 0000000..44d7088
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/logging/AppenderConsole.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.billing.azure.logging;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.ConsoleAppender;
+import com.epam.datalab.exceptions.InitializationException;
+import com.fasterxml.jackson.annotation.JsonClassDescription;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+
+/**
+ * Console appender for logging.
+ */
+@JsonTypeName("console")
+@JsonClassDescription(
+        "Console log appender.\n" +
+                "Output log data to console. Does not have any properties.\n" +
+                "  - type: console"
+)
+public class AppenderConsole extends AppenderBase {
+
+    @Override
+    public void configure(LoggerContext context) throws InitializationException {
+        super.configure(context, "console-appender", new ConsoleAppender<ILoggingEvent>());
+    }
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/logging/AppenderFile.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/logging/AppenderFile.java
new file mode 100644
index 0000000..99ad32e
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/logging/AppenderFile.java
@@ -0,0 +1,200 @@
+/*
+ * 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.datalab.billing.azure.logging;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.CoreConstants;
+import ch.qos.logback.core.FileAppender;
+import ch.qos.logback.core.rolling.DefaultTimeBasedFileNamingAndTriggeringPolicy;
+import ch.qos.logback.core.rolling.RollingFileAppender;
+import ch.qos.logback.core.rolling.TimeBasedFileNamingAndTriggeringPolicy;
+import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
+import com.epam.datalab.exceptions.InitializationException;
+import com.fasterxml.jackson.annotation.JsonClassDescription;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeName;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+/**
+ * File appender for logging. Support rolling files and archiving.
+ */
+@JsonTypeName("file")
+@JsonClassDescription(
+        "File log appender.\n" +
+                "Output log data to the file, if property archive is set to true then rolling\n" +
+                "mode is enabled. If archivedLogFilenamePattern ends with .gz or .zip extension\n" +
+                "then old log file will be compressed.\n" +
+                "  - type: file\n" +
+                "    currentLogFilename: <[path/]filename.log>  - pattern for log file naming.\n" +
+                "    [archive: <true | false>]                  - rolling log files or none.\n" +
+                "    [archivedLogFilenamePattern: <[path/]filename-%d{yyyy-MM-dd}.log[.gz | .zip]>]\n" +
+                "                                               - pattern for naming the archive log\n" +
+                "                                                 files.\n" +
+                "    [archivedFileCount: <number_of_days>]      - number of archive log file history."
+)
+public class AppenderFile extends AppenderBase {
+
+    /**
+     * The name of current log file.
+     */
+    @JsonProperty
+    private String currentLogFilename;
+
+    /**
+     * Flag for archive of old files.
+     */
+    @JsonProperty
+    private boolean archive = false;
+
+    /**
+     * Pattern for naming archive files. The compression mode depending on last
+     * letters of the fileNamePatternStr. Patterns ending with .gz imply GZIP
+     * compression, endings with '.zip' imply ZIP compression. Otherwise and by
+     * default, there is no compression.
+     */
+    @JsonProperty
+    private String archivedLogFilenamePattern;
+
+    /**
+     * The maximum number of archive files to keep..
+     */
+    @JsonProperty
+    private int archivedFileCount = CoreConstants.UNBOUND_HISTORY;
+
+
+    /**
+     * Return the name of current log file.
+     */
+    public String getCurrentLogFilename() {
+        return currentLogFilename;
+    }
+
+    /**
+     * Set the name of current log file.
+     */
+    public void setCurrentLogFilename(String currentLogFilename) {
+        this.currentLogFilename = currentLogFilename;
+    }
+
+    /**
+     * Return the flag for archive of old files.
+     */
+    public boolean getArchive() {
+        return archive;
+    }
+
+    /**
+     * Set the flag for archive of old files.
+     */
+    public void setArchive(boolean archive) {
+        this.archive = archive;
+    }
+
+    /**
+     * Return the pattern for naming archive files.
+     */
+    public String getArchivedLogFilenamePattern() {
+        return archivedLogFilenamePattern;
+    }
+
+    /**
+     * Set pattern for naming archive files. The compression mode depending on last
+     * letters of the fileNamePatternStr. Patterns ending with .gz imply GZIP
+     * compression, endings with '.zip' imply ZIP compression. Otherwise and by
+     * default, there is no compression.
+     * For example,
+     * /logs/application-%d{yyyy-MM-dd}.log.gz
+     */
+    public void setArchivedLogFilenamePattern(String archivedLogFilenamePattern) {
+        this.archivedLogFilenamePattern = archivedLogFilenamePattern;
+    }
+
+    /**
+     * Return the maximum number of archive files to keep..
+     */
+    public int getArchivedFileCount() {
+        return archivedFileCount;
+    }
+
+    /**
+     * Set the maximum number of archive files to keep..
+     */
+    public void setArchivedFileCount(int archivedFileCount) {
+        this.archivedFileCount = archivedFileCount;
+    }
+
+
+    @Override
+    public void configure(LoggerContext context) throws InitializationException {
+        if (currentLogFilename == null || currentLogFilename.trim().isEmpty()) {
+            throw new InitializationException("Configuration property logging.appenders.currentLogFilename cannot be null.");
+        }
+        super.configure(context, "file-appender", (archive ? getRollingFileAppender(context) : getFileAppender()));
+    }
+
+    /**
+     * Create and return synchronous the file appender.
+     */
+    private FileAppender<ILoggingEvent> getFileAppender() {
+        FileAppender<ILoggingEvent> appender = new FileAppender<>();
+        appender.setFile(currentLogFilename);
+        appender.setAppend(true);
+        return appender;
+    }
+
+    /**
+     * Create and return synchronous the rolling file appender.
+     *
+     * @param context the context of logger.
+     */
+    private RollingFileAppender<ILoggingEvent> getRollingFileAppender(LoggerContext context) throws InitializationException {
+        if (archivedLogFilenamePattern == null || archivedLogFilenamePattern.trim().isEmpty()) {
+            throw new InitializationException("Configuration property logging.appenders.archivedLogFilenamePattern cannot be null.");
+        }
+        RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();
+        appender.setFile(currentLogFilename);
+        appender.setAppend(true);
+
+        TimeBasedFileNamingAndTriggeringPolicy<ILoggingEvent> triggerPolicy = new DefaultTimeBasedFileNamingAndTriggeringPolicy<>();
+        triggerPolicy.setContext(context);
+
+        TimeBasedRollingPolicy<ILoggingEvent> rollPolicy = new TimeBasedRollingPolicy<>();
+        rollPolicy.setContext(context);
+        rollPolicy.setParent(appender);
+        rollPolicy.setFileNamePattern(archivedLogFilenamePattern);
+        rollPolicy.setMaxHistory(archivedFileCount);
+        rollPolicy.setTimeBasedFileNamingAndTriggeringPolicy(triggerPolicy);
+        rollPolicy.start();
+        appender.setRollingPolicy(rollPolicy);
+
+        return appender;
+    }
+
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("currentLogFilename", currentLogFilename)
+                .add("archive", archive)
+                .add("archivedLogFilenamePattern", archivedLogFilenamePattern)
+                .add("archivedFileCount", archivedFileCount);
+    }
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/model/AzureDailyResourceInvoice.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/model/AzureDailyResourceInvoice.java
new file mode 100644
index 0000000..5b8c0ac
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/model/AzureDailyResourceInvoice.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab.billing.azure.model;
+
+import com.epam.datalab.billing.azure.MongoDocument;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@Builder
+@EqualsAndHashCode(callSuper = true)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class AzureDailyResourceInvoice extends MongoDocument<AzureDailyResourceInvoice> {
+    @JsonProperty
+    private String datalabId;
+    @JsonProperty
+    private String meterCategory;
+    @JsonProperty
+    private String usageStartDate;
+    @JsonProperty
+    private String usageEndDate;
+    @JsonProperty
+    private String day;
+    @JsonProperty
+    private double cost;
+    @JsonProperty
+    private String currencyCode;
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/model/AzureDatalabBillableResource.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/model/AzureDatalabBillableResource.java
new file mode 100644
index 0000000..6eb194b
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/model/AzureDatalabBillableResource.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.datalab.billing.azure.model;
+
+import com.epam.datalab.billing.DatalabResourceType;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class AzureDatalabBillableResource {
+    private String id;
+    private DatalabResourceType type;
+    private String user;
+    private String project;
+    private String notebookId;
+    private String resourceName;
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/model/BillingPeriod.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/model/BillingPeriod.java
new file mode 100644
index 0000000..23083bb
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/model/BillingPeriod.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.billing.azure.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BillingPeriod {
+    @JsonProperty
+    private Date from;
+    @JsonProperty
+    private Date to;
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/rate/AzureRateCardClient.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/rate/AzureRateCardClient.java
new file mode 100644
index 0000000..a3f66c0
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/rate/AzureRateCardClient.java
@@ -0,0 +1,109 @@
+/*
+ * 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.datalab.billing.azure.rate;
+
+import com.epam.datalab.billing.azure.config.BillingConfigurationAzure;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.Header;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolException;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultRedirectStrategy;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.function.Predicate;
+
+@Slf4j
+public class AzureRateCardClient {
+    private ObjectMapper objectMapper = new ObjectMapper();
+    public static final String MAIN_RATE_KEY = "0";
+    private BillingConfigurationAzure billingConfigurationAzure;
+    private String authToken;
+
+    public AzureRateCardClient(BillingConfigurationAzure billingConfigurationAzure, String authToken) {
+        this.billingConfigurationAzure = billingConfigurationAzure;
+        this.authToken = authToken;
+    }
+
+    public RateCardResponse getRateCard() throws IOException, URISyntaxException {
+
+        try (CloseableHttpClient httpClient = HttpClients.custom()
+                .setRedirectStrategy(new CustomRedirectWithoutAuthorizationStrategy())
+                .build()) {
+            final URIBuilder uriBuilder = new URIBuilder("https://management.azure.com/subscriptions/" +
+                    billingConfigurationAzure.getSubscriptionId() + "/providers/Microsoft.Commerce/RateCard")
+                    .addParameter("api-version", "2016-08-31-preview")
+                    .addParameter("$filter", String.format("OfferDurableId eq '%s' and Currency eq '%s' and Locale " +
+                                    "eq '%s' and RegionInfo eq '%s'", billingConfigurationAzure.getOfferNumber(),
+                            billingConfigurationAzure.getCurrency(), billingConfigurationAzure.getLocale(),
+                            billingConfigurationAzure.getRegionInfo()));
+
+            final HttpGet request = new HttpGet(uriBuilder.build());
+            request.addHeader("Authorization", String.format("Bearer %s", authToken));
+            request.addHeader(HttpHeaders.ACCEPT, "application/json");
+            return objectMapper.readValue(EntityUtils.toString
+                    (httpClient.execute(request).getEntity()), RateCardResponse.class);
+        } catch (IOException | URISyntaxException e) {
+            log.error("Cannot retrieve rate card due to ", e);
+            throw e;
+        }
+    }
+
+    class CustomRedirectWithoutAuthorizationStrategy extends DefaultRedirectStrategy {
+        @Override
+        public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws
+                ProtocolException {
+            if (HttpGet.METHOD_NAME.equals(request.getRequestLine().getMethod())) {
+                return httpGetWithoutAuthorization(request, response, context);
+            } else {
+                return super.getRedirect(request, response, context);
+            }
+        }
+
+        private HttpUriRequest httpGetWithoutAuthorization(HttpRequest request, HttpResponse response, HttpContext
+                context) throws ProtocolException {
+            return new HttpGet(getLocationURI(request, response, context)) {
+                @Override
+                public void setHeaders(Header[] headers) {
+                    super.setHeaders(filter(headers, h -> !h.getName().equals(HttpHeaders.AUTHORIZATION)));
+                }
+
+                private Header[] filter(Header[] headers, Predicate<Header> predicate) {
+                    return Arrays.stream(headers)
+                            .filter(predicate)
+                            .toArray(Header[]::new);
+                }
+            };
+        }
+    }
+
+
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/rate/Meter.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/rate/Meter.java
new file mode 100644
index 0000000..dd4e994
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/rate/Meter.java
@@ -0,0 +1,52 @@
+/*
+ * 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.datalab.billing.azure.rate;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class Meter {
+    @JsonProperty("EffectiveDate")
+    private String effectiveDate;
+    @JsonProperty("IncludedQuantity")
+    private long includedQuantity;
+    @JsonProperty("MeterCategory")
+    private String meterCategory;
+    @JsonProperty("MeterId")
+    private String meterId;
+    @JsonProperty("MeterName")
+    private String meterName;
+    @JsonProperty("MeterRates")
+    private Map<String, Double> meterRates;
+    @JsonProperty("MeterRegion")
+    private String meterRegion;
+    @JsonProperty("MeterStatus")
+    private String meterStatus;
+    @JsonProperty("MeterSubCategory")
+    private String meterSubCategory;
+    @JsonProperty("MeterTags")
+    private List<Object> meterTags;
+    @JsonProperty("Unit")
+    private String unit;
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/rate/RateCardResponse.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/rate/RateCardResponse.java
new file mode 100644
index 0000000..de6a5fa
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/rate/RateCardResponse.java
@@ -0,0 +1,41 @@
+/*
+ * 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.datalab.billing.azure.rate;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.ToString;
+
+import java.util.List;
+
+@Data
+@ToString(exclude = "meters")
+public class RateCardResponse {
+    @JsonProperty("OfferTerms")
+    private List<Object> offerTerms;
+    @JsonProperty("Meters")
+    private List<Meter> meters;
+    @JsonProperty("Currency")
+    private String currency;
+    @JsonProperty("Locale")
+    private String locale;
+    @JsonProperty("IsTaxIncluded")
+    private boolean taxIncluded;
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/AzureUsageAggregateClient.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/AzureUsageAggregateClient.java
new file mode 100644
index 0000000..c961537
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/AzureUsageAggregateClient.java
@@ -0,0 +1,103 @@
+/*
+ * 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.datalab.billing.azure.usage;
+
+import com.epam.datalab.billing.azure.config.BillingConfigurationAzure;
+import com.epam.datalab.exceptions.DatalabException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpHeaders;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Objects;
+
+@Slf4j
+public class AzureUsageAggregateClient {
+    private ObjectMapper objectMapper = new ObjectMapper();
+    private BillingConfigurationAzure billingConfigurationAzure;
+    private String authToken;
+
+    public AzureUsageAggregateClient(BillingConfigurationAzure billingConfigurationAzure, String authToken) {
+        this.billingConfigurationAzure = billingConfigurationAzure;
+        this.authToken = authToken;
+    }
+
+    public UsageAggregateResponse getUsageAggregateResponse(String from, String to) throws IOException,
+            URISyntaxException {
+        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+
+            final URIBuilder uriBuilder = new URIBuilder("https://management.azure.com/subscriptions/" +
+                    billingConfigurationAzure.getSubscriptionId() + "/providers/Microsoft" +
+                    ".Commerce/UsageAggregates")
+                    .addParameter("api-version", "2015-06-01-preview")
+                    .addParameter("reportedStartTime", from)
+                    .addParameter("reportedEndTime", to)
+                    .addParameter("aggregationGranularity", "daily")
+                    .addParameter("showDetails", "false");
+            final HttpGet request = new HttpGet(uriBuilder.build());
+            request.addHeader("Authorization", String.format("Bearer %s", authToken));
+            request.addHeader(HttpHeaders.ACCEPT, "application/json");
+            final UsageAggregateResponse usageAggregateResponse = objectMapper.readValue(EntityUtils.toString
+                    (httpClient.execute(request).getEntity()), UsageAggregateResponse.class);
+            return postProcess(usageAggregateResponse);
+        } catch (URISyntaxException e) {
+            log.error("Cannot retrieve usage detail due to ", e);
+            throw e;
+        }
+    }
+
+
+    public UsageAggregateResponse getUsageAggregateResponse(String nextUrl) throws IOException {
+        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+            final HttpGet request = new HttpGet(nextUrl);
+            request.addHeader("Authorization", String.format("Bearer %s", authToken));
+            request.addHeader(HttpHeaders.ACCEPT, "application/json");
+            final UsageAggregateResponse usageAggregateResponse = objectMapper.readValue(EntityUtils.toString
+                    (httpClient.execute(request).getEntity()), UsageAggregateResponse.class);
+            return postProcess(usageAggregateResponse);
+        }
+    }
+
+    public void setAuthToken(String authToken) {
+        this.authToken = authToken;
+    }
+
+    private UsageAggregateResponse postProcess(UsageAggregateResponse usageAggregateResponse) {
+        usageAggregateResponse.getValue()
+                .stream()
+                .filter(r -> Objects.nonNull(r.getProperties().getInstanceData()))
+                .forEach(r -> r.getProperties().setParsedInstanceData(toInstanceData(r)));
+        return usageAggregateResponse;
+    }
+
+    private InstanceData toInstanceData(UsageAggregateRecord r) {
+        try {
+            return objectMapper.readValue(r.getProperties().getInstanceData(), InstanceData.class);
+        } catch (IOException e) {
+            throw new DatalabException("Can not parse instance data", e);
+        }
+    }
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/InstanceData.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/InstanceData.java
new file mode 100644
index 0000000..4e56600
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/InstanceData.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab.billing.azure.usage;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class InstanceData {
+    @JsonProperty("Microsoft.Resources")
+    private MicrosoftResources microsoftResources;
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/MicrosoftResources.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/MicrosoftResources.java
new file mode 100644
index 0000000..61d6700
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/MicrosoftResources.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab.billing.azure.usage;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+public class MicrosoftResources {
+    @JsonProperty
+    private String resourceUri;
+    @JsonProperty
+    private String location;
+    @JsonProperty
+    private Map<String, String> tags;
+    @JsonProperty
+    private Map<String, String> additionalInfo;
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/UsageAggregateRecord.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/UsageAggregateRecord.java
new file mode 100644
index 0000000..af39a27
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/UsageAggregateRecord.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.billing.azure.usage;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class UsageAggregateRecord {
+    @JsonProperty
+    private String id;
+    @JsonProperty
+    private String name;
+    @JsonProperty
+    private String type;
+    @JsonProperty
+    private UsageAggregateRecordProperties properties;
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/UsageAggregateRecordProperties.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/UsageAggregateRecordProperties.java
new file mode 100644
index 0000000..938530d
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/UsageAggregateRecordProperties.java
@@ -0,0 +1,54 @@
+/*
+ * 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.datalab.billing.azure.usage;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+public class UsageAggregateRecordProperties {
+    @JsonProperty
+    private String subscriptionId;
+    @JsonProperty
+    private String usageStartTime;
+    @JsonProperty
+    private String usageEndTime;
+    @JsonProperty
+    private String meterName;
+    @JsonProperty
+    private String meterRegion;
+    @JsonProperty
+    private String meterCategory;
+    @JsonProperty
+    private String meterSubCategory;
+    @JsonProperty
+    private String unit;
+    @JsonProperty
+    private String instanceData;
+    private InstanceData parsedInstanceData;
+    @JsonProperty
+    private String meterId;
+    @JsonProperty
+    private Map<String, String> infoFields;
+    @JsonProperty
+    private double quantity;
+}
diff --git a/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/UsageAggregateResponse.java b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/UsageAggregateResponse.java
new file mode 100644
index 0000000..ecdf3a6
--- /dev/null
+++ b/services/billing-azure/src/main/java/com/epam/datalab/billing/azure/usage/UsageAggregateResponse.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.datalab.billing.azure.usage;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class UsageAggregateResponse {
+    @JsonProperty
+    private List<UsageAggregateRecord> value;
+    @JsonProperty
+    private String nextLink;
+}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/AzureInvoiceCalculationService.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/AzureInvoiceCalculationService.java
deleted file mode 100644
index 441475e..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/AzureInvoiceCalculationService.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * 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.billing.azure;
-
-import com.epam.dlab.billing.BillingCalculationUtils;
-import com.epam.dlab.billing.azure.config.BillingConfigurationAzure;
-import com.epam.dlab.billing.azure.model.AzureDailyResourceInvoice;
-import com.epam.dlab.billing.azure.rate.AzureRateCardClient;
-import com.epam.dlab.billing.azure.rate.Meter;
-import com.epam.dlab.billing.azure.rate.RateCardResponse;
-import com.epam.dlab.billing.azure.usage.AzureUsageAggregateClient;
-import com.epam.dlab.billing.azure.usage.UsageAggregateRecord;
-import com.epam.dlab.billing.azure.usage.UsageAggregateResponse;
-import com.epam.dlab.exceptions.DlabException;
-import com.microsoft.azure.AzureEnvironment;
-import com.microsoft.azure.credentials.ApplicationTokenCredentials;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * Filters billing data and calculate prices for each
- * resource using combination of Microsoft Azure RateCard API and Usage API
- */
-@Slf4j
-public class AzureInvoiceCalculationService {
-
-	/**
-	 * According to Microsoft Azure documentation
-	 * https://docs.microsoft.com/en-us/azure/active-directory/active-directory-configurable-token-lifetimes
-	 * min TTL time of token 10 minutes
-	 */
-	private static final long MAX_AUTH_TOKEN_TTL_MILLIS = 9L * 60L * 1000L;
-
-	private BillingConfigurationAzure billingConfigurationAzure;
-
-	/**
-	 * Constructs service class
-	 *
-	 * @param billingConfigurationAzure contains <code>billing-azure</code> module configuration
-	 */
-	public AzureInvoiceCalculationService(BillingConfigurationAzure billingConfigurationAzure) {
-		this.billingConfigurationAzure = billingConfigurationAzure;
-	}
-
-	/**
-	 * Prepares invoice records aggregated by day
-	 *
-	 * @param from start usage period
-	 * @param to   end usage period
-	 * @return list of invoice records for each meter category aggregated by day
-	 */
-	public List<AzureDailyResourceInvoice> generateInvoiceData(String from, String to) {
-
-		long refreshTokenTime = System.currentTimeMillis() + MAX_AUTH_TOKEN_TTL_MILLIS;
-
-		String authenticationToken = getNewToken();
-		AzureRateCardClient azureRateCardClient = new AzureRateCardClient(billingConfigurationAzure,
-                authenticationToken);
-		AzureUsageAggregateClient azureUsageAggregateClient = new AzureUsageAggregateClient(billingConfigurationAzure,
-                authenticationToken);
-
-		List<AzureDailyResourceInvoice> invoiceData = new ArrayList<>();
-
-		try {
-
-			UsageAggregateResponse usageAggregateResponse = null;
-			Map<String, Meter> rates = transformRates(azureRateCardClient.getRateCard());
-
-			do {
-
-				if (usageAggregateResponse != null && StringUtils.isNotEmpty(usageAggregateResponse.getNextLink())) {
-					log.info("Get usage of resources using link {}", usageAggregateResponse.getNextLink());
-					usageAggregateResponse = azureUsageAggregateClient.getUsageAggregateResponse
-                            (usageAggregateResponse.getNextLink());
-					log.info("Received usage of resources. Items {} ", usageAggregateResponse.getValue() != null ?
-							usageAggregateResponse.getValue().size() : 0);
-					log.info("Next link is {}", usageAggregateResponse.getNextLink());
-				} else if (usageAggregateResponse == null) {
-					log.info("Get usage of resources from {} to {}", from, to);
-					usageAggregateResponse = azureUsageAggregateClient.getUsageAggregateResponse(from, to);
-					log.info("Received usage of resources. Items {} ", usageAggregateResponse.getValue() != null ?
-							usageAggregateResponse.getValue().size() : 0);
-					log.info("Next link is {}", usageAggregateResponse.getNextLink());
-				}
-
-				invoiceData.addAll(generateBillingInfo(rates, usageAggregateResponse));
-
-				if (System.currentTimeMillis() > refreshTokenTime) {
-					authenticationToken = getNewToken();
-					azureUsageAggregateClient.setAuthToken(authenticationToken);
-				}
-
-			} while (StringUtils.isNotEmpty(usageAggregateResponse.getNextLink()));
-
-		} catch (IOException | RuntimeException | URISyntaxException e) {
-			log.error("Cannot calculate billing information", e);
-			throw new DlabException("Cannot prepare invoice data", e);
-		}
-
-		return invoiceData;
-	}
-
-	private List<AzureDailyResourceInvoice> generateBillingInfo(Map<String, Meter> rates, UsageAggregateResponse
-            usageAggregateResponse) {
-		List<UsageAggregateRecord> usageAggregateRecordList = usageAggregateResponse.getValue();
-		List<AzureDailyResourceInvoice> invoices = new ArrayList<>();
-
-		if (usageAggregateRecordList != null && !usageAggregateRecordList.isEmpty()) {
-			log.info("Processing {} usage records", usageAggregateRecordList.size());
-			usageAggregateRecordList = usageAggregateRecordList.stream().filter(e ->
-					matchProperStructure(e) && isBillableDlabResource(e))
-					.collect(Collectors.toList());
-
-			log.info("Applicable records number is {}", usageAggregateRecordList.size());
-
-			for (UsageAggregateRecord record : usageAggregateRecordList) {
-				invoices.add(calculateInvoice(rates, record, record.getProperties().getParsedInstanceData()
-						.getMicrosoftResources().getTags().get("Name")));
-			}
-		} else {
-			log.error("No usage records in response.");
-		}
-
-		return invoices;
-	}
-
-	private Map<String, Meter> transformRates(RateCardResponse rateCardResponse) {
-		Map<String, Meter> rates = new HashMap<>();
-		for (Meter meter : rateCardResponse.getMeters()) {
-			rates.put(meter.getMeterId(), meter);
-		}
-
-		return rates;
-	}
-
-	private boolean matchProperStructure(UsageAggregateRecord record) {
-		if (record.getProperties() == null) {
-			return false;
-		}
-
-		if (record.getProperties().getMeterId() == null || record.getProperties().getMeterId().isEmpty()) {
-			return false;
-		}
-
-		return !(record.getProperties().getParsedInstanceData() == null
-				|| record.getProperties().getParsedInstanceData().getMicrosoftResources() == null
-				|| record.getProperties().getParsedInstanceData().getMicrosoftResources().getTags() == null
-				|| record.getProperties().getParsedInstanceData().getMicrosoftResources().getTags().isEmpty());
-	}
-
-	private boolean isBillableDlabResource(UsageAggregateRecord record) {
-		String dlabId = record.getProperties().getParsedInstanceData().getMicrosoftResources().getTags().get("Name");
-		return dlabId != null && !dlabId.isEmpty() && dlabId.startsWith(billingConfigurationAzure.getSbn());
-	}
-
-	private AzureDailyResourceInvoice calculateInvoice(Map<String, Meter> rates, UsageAggregateRecord record, String dlabId) {
-		String meterId = record.getProperties().getMeterId();
-		Meter rateCard = rates.get(meterId);
-
-		if (rateCard != null) {
-			Map<String, Double> meterRates = rateCard.getMeterRates();
-			if (meterRates != null) {
-				Double rate = meterRates.get(AzureRateCardClient.MAIN_RATE_KEY);
-				if (rate != null) {
-					return AzureDailyResourceInvoice.builder()
-							.dlabId(dlabId)
-							.usageStartDate(getDay(record.getProperties().getUsageStartTime()))
-							.usageEndDate(getDay(record.getProperties().getUsageEndTime()))
-							.meterCategory(record.getProperties().getMeterCategory())
-							.cost(BillingCalculationUtils.round(rate * record.getProperties().getQuantity(), 3))
-							.day(getDay(record.getProperties().getUsageStartTime()))
-							.currencyCode(billingConfigurationAzure.getCurrency())
-							.build();
-				} else {
-					log.error("Rate Card {} has no rate for meter id {} and rate id {}. Skip record {}.",
-							rateCard, meterId, AzureRateCardClient.MAIN_RATE_KEY, record);
-				}
-			} else {
-				log.error("Rate Card {} has no meter rates fro meter id {}. Skip record {}",
-						rateCard, meterId, record);
-			}
-		} else {
-			log.error("Meter rate {} form usage aggregate is not found in rate card. Skip record {}.", meterId, record);
-		}
-
-		return null;
-	}
-
-	private String getNewToken() {
-		try {
-			log.info("Requesting authentication token ... ");
-			ApplicationTokenCredentials applicationTokenCredentials = new ApplicationTokenCredentials(
-					billingConfigurationAzure.getClientId(),
-					billingConfigurationAzure.getTenantId(),
-					billingConfigurationAzure.getClientSecret(),
-					AzureEnvironment.AZURE);
-
-			return applicationTokenCredentials.getToken(AzureEnvironment.AZURE.resourceManagerEndpoint());
-		} catch (IOException e) {
-			log.error("Cannot retrieve authentication token due to", e);
-			throw new DlabException("Cannot retrieve authentication token", e);
-		}
-	}
-
-	private String getDay(String dateTime) {
-		if (dateTime != null) {
-			String[] parts = dateTime.split("T");
-			if (parts.length == 2) {
-				return parts[0];
-			}
-		}
-
-		log.error("Wrong usage date format {} ", dateTime);
-		return null;
-	}
-
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/BillingAzureApplication.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/BillingAzureApplication.java
deleted file mode 100644
index 1a40767..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/BillingAzureApplication.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.billing.azure;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
-
-@SpringBootApplication
-@EnableMongoRepositories
-@EnableConfigurationProperties
-public class BillingAzureApplication {
-
-    public static void main(String[] args) {
-        SpringApplication.run(BillingAzureApplication.class, args);
-    }
-
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/CalculateBillingService.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/CalculateBillingService.java
deleted file mode 100644
index 2f265c0..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/CalculateBillingService.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.billing.azure;
-
-import com.epam.dlab.dto.billing.BillingData;
-
-import java.util.List;
-
-@FunctionalInterface
-public interface CalculateBillingService {
-    List<BillingData> getBillingData();
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/CalculateBillingServiceImpl.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/CalculateBillingServiceImpl.java
deleted file mode 100644
index 7b29677..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/CalculateBillingServiceImpl.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * 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.billing.azure;
-
-import com.epam.dlab.MongoKeyWords;
-import com.epam.dlab.billing.azure.config.BillingConfigurationAzure;
-import com.epam.dlab.billing.azure.model.AzureDailyResourceInvoice;
-import com.epam.dlab.billing.azure.model.BillingPeriod;
-import com.epam.dlab.dto.billing.BillingData;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.model.azure.AzureAuthFile;
-import com.epam.dlab.util.mongo.modules.IsoDateModule;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.mongodb.BasicDBObject;
-import com.mongodb.client.model.Filters;
-import com.mongodb.client.model.UpdateOptions;
-import com.mongodb.client.result.UpdateResult;
-import lombok.extern.slf4j.Slf4j;
-import org.bson.Document;
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-import org.joda.time.format.DateTimeFormat;
-import org.joda.time.format.DateTimeFormatter;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.time.LocalDate;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-@Slf4j
-@Service
-public class CalculateBillingServiceImpl implements CalculateBillingService {
-    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z");
-    private static final String SCHEDULER_ID = "azureBillingScheduler";
-    private final BillingConfigurationAzure billingConfigurationAzure;
-    private final MongoDbBillingClient mongoDbBillingClient;
-    private ObjectMapper objectMapper;
-
-    @Autowired
-    public CalculateBillingServiceImpl(BillingConfigurationAzure configuration) throws IOException {
-        billingConfigurationAzure = configuration;
-        objectMapper = new ObjectMapper().registerModule(new IsoDateModule());
-        Path path = Paths.get(billingConfigurationAzure.getAuthenticationFile());
-
-        if (path.toFile().exists()) {
-            log.info("Read and override configs using auth file");
-            try {
-                AzureAuthFile azureAuthFile = new ObjectMapper().readValue(path.toFile(), AzureAuthFile.class);
-                this.billingConfigurationAzure.setClientId(azureAuthFile.getClientId());
-                this.billingConfigurationAzure.setClientSecret(azureAuthFile.getClientSecret());
-                this.billingConfigurationAzure.setTenantId(azureAuthFile.getTenantId());
-                this.billingConfigurationAzure.setSubscriptionId(azureAuthFile.getSubscriptionId());
-            } catch (IOException e) {
-                log.error("Cannot read configuration file", e);
-                throw e;
-            }
-            log.info("Configs from auth file are used");
-        } else {
-            log.info("Configs from yml file are used");
-        }
-
-        this.mongoDbBillingClient = new MongoDbBillingClient
-                (billingConfigurationAzure.getAggregationOutputMongoDataSource().getHost(),
-                        billingConfigurationAzure.getAggregationOutputMongoDataSource().getPort(),
-                        billingConfigurationAzure.getAggregationOutputMongoDataSource().getDatabase(),
-                        billingConfigurationAzure.getAggregationOutputMongoDataSource().getUsername(),
-                        billingConfigurationAzure.getAggregationOutputMongoDataSource().getPassword());
-    }
-
-    @Override
-    public List<BillingData> getBillingData() {
-        try {
-            BillingPeriod billingPeriod = getBillingPeriod();
-            DateTime currentTime = new DateTime().withZone(DateTimeZone.UTC);
-            if (billingPeriod == null) {
-                saveBillingPeriod(initialSchedulerInfo(currentTime));
-            } else {
-                log.info("Billing period from db is {}", billingPeriod);
-
-                if (shouldTriggerJobByTime(currentTime, billingPeriod)) {
-                    List<BillingData> billingData = getBillingData(billingPeriod);
-                    boolean hasNew = !billingData.isEmpty();
-                    updateBillingPeriod(billingPeriod, currentTime, hasNew);
-                    return billingData;
-                }
-            }
-        } catch (RuntimeException e) {
-            log.error("Cannot update billing information", e);
-        }
-        return Collections.emptyList();
-    }
-
-    private BillingPeriod initialSchedulerInfo(DateTime currentTime) {
-
-        BillingPeriod initialBillingPeriod = new BillingPeriod();
-        initialBillingPeriod.setFrom(currentTime.minusDays(2).toDateMidnight().toDate());
-        initialBillingPeriod.setTo(currentTime.toDateMidnight().toDate());
-
-        log.info("Initial scheduler info {}", initialBillingPeriod);
-
-        return initialBillingPeriod;
-
-    }
-
-    private boolean shouldTriggerJobByTime(DateTime currentTime, BillingPeriod billingPeriod) {
-
-        DateTime dateTimeToFromBillingPeriod = new DateTime(billingPeriod.getTo()).withZone(DateTimeZone.UTC);
-
-        log.info("Comparing current time[{}, {}] and from scheduler info [{}, {}]", currentTime,
-                currentTime.toDateMidnight(),
-                dateTimeToFromBillingPeriod, dateTimeToFromBillingPeriod.toDateMidnight());
-
-        if (currentTime.toDateMidnight().isAfter(dateTimeToFromBillingPeriod.toDateMidnight())
-                || currentTime.toDateMidnight().isEqual(dateTimeToFromBillingPeriod.toDateMidnight())) {
-            log.info("Should trigger the job by time");
-            return true;
-        }
-
-        log.info("Should not trigger the job by time");
-        return false;
-    }
-
-    private List<BillingData> getBillingData(BillingPeriod billingPeriod) {
-        AzureInvoiceCalculationService azureInvoiceCalculationService
-                = new AzureInvoiceCalculationService(billingConfigurationAzure);
-
-        List<AzureDailyResourceInvoice> dailyInvoices = azureInvoiceCalculationService.generateInvoiceData(
-                DATE_TIME_FORMATTER.print(new DateTime(billingPeriod.getFrom()).withZone(DateTimeZone.UTC)),
-                DATE_TIME_FORMATTER.print(new DateTime(billingPeriod.getTo()).withZone(DateTimeZone.UTC)));
-
-        if (!dailyInvoices.isEmpty()) {
-            return dailyInvoices
-                    .stream()
-                    .map(this::toBillingData)
-                    .collect(Collectors.toList());
-        } else {
-            log.warn("Daily invoices is empty for period {}", billingPeriod);
-            return Collections.emptyList();
-        }
-    }
-
-    private void updateBillingPeriod(BillingPeriod billingPeriod, DateTime currentTime, boolean updates) {
-
-        try {
-            mongoDbBillingClient.getDatabase().getCollection(MongoKeyWords.AZURE_BILLING_SCHEDULER_HISTORY).insertOne(
-                    Document.parse(objectMapper.writeValueAsString(billingPeriod)).append("updates", updates));
-            log.debug("History of billing periods is updated with {}",
-                    objectMapper.writeValueAsString(billingPeriod));
-        } catch (JsonProcessingException e) {
-            log.error("Cannot update history of billing periods", e);
-
-        }
-
-        billingPeriod.setFrom(billingPeriod.getTo());
-
-        if (new DateTime(billingPeriod.getFrom()).withZone(DateTimeZone.UTC).toDateMidnight()
-                .isEqual(currentTime.toDateMidnight())) {
-
-            log.info("Setting billing to one day later");
-            billingPeriod.setTo(currentTime.plusDays(1).toDateMidnight().toDate());
-
-        } else {
-            billingPeriod.setTo(currentTime.toDateMidnight().toDate());
-        }
-
-        saveBillingPeriod(billingPeriod);
-    }
-
-    private boolean saveBillingPeriod(BillingPeriod billingPeriod) {
-        log.debug("Saving billing period {}", billingPeriod);
-
-        try {
-            UpdateResult updateResult = mongoDbBillingClient.getDatabase().getCollection(MongoKeyWords.AZURE_BILLING_SCHEDULER)
-                    .updateMany(Filters.eq(MongoKeyWords.MONGO_ID, SCHEDULER_ID),
-                            new BasicDBObject("$set",
-                                    Document.parse(objectMapper.writeValueAsString(billingPeriod))
-                                            .append(MongoKeyWords.MONGO_ID, SCHEDULER_ID))
-                            , new UpdateOptions().upsert(true)
-                    );
-
-            log.debug("Billing period save operation result is {}", updateResult);
-            return true;
-        } catch (JsonProcessingException e) {
-            log.error("Cannot save billing period", e);
-        }
-
-        return false;
-    }
-
-    private BillingPeriod getBillingPeriod() {
-        log.debug("Get billing period");
-
-        try {
-            Document document = mongoDbBillingClient.getDatabase().getCollection(MongoKeyWords.AZURE_BILLING_SCHEDULER)
-                    .find(Filters.eq(MongoKeyWords.MONGO_ID, SCHEDULER_ID)).first();
-
-            log.debug("Retrieved billing period document {}", document);
-            if (document != null) {
-                return objectMapper.readValue(document.toJson(), BillingPeriod.class);
-            }
-
-            return null;
-
-        } catch (IOException e) {
-            log.error("Cannot save billing period", e);
-            throw new DlabException("Cannot parse string", e);
-        }
-    }
-
-    private BillingData toBillingData(AzureDailyResourceInvoice billingData) {
-        return BillingData.builder()
-                .tag(billingData.getDlabId().toLowerCase())
-                .usageDateFrom(Optional.ofNullable(billingData.getUsageStartDate()).map(LocalDate::parse).orElse(null))
-                .usageDateTo(Optional.ofNullable(billingData.getUsageEndDate()).map(LocalDate::parse).orElse(null))
-                .usageDate(billingData.getDay())
-                .product(billingData.getMeterCategory())
-                .cost(billingData.getCost())
-                .currency(billingData.getCurrencyCode())
-                .build();
-    }
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/MongoDbBillingClient.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/MongoDbBillingClient.java
deleted file mode 100644
index b5ae73b..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/MongoDbBillingClient.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.billing.azure;
-
-import com.google.common.collect.Lists;
-import com.mongodb.MongoClient;
-import com.mongodb.MongoCredential;
-import com.mongodb.ServerAddress;
-import com.mongodb.client.MongoDatabase;
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-public class MongoDbBillingClient {
-
-    private MongoClient client;
-    private MongoDatabase database;
-
-    public MongoDbBillingClient(String host, int port, String databaseName, String username, String password) {
-        this.client = new MongoClient(new ServerAddress(host, port),
-                Lists.newArrayList(MongoCredential.createCredential(username,
-                        databaseName, password.toCharArray())));
-
-        this.database = client.getDatabase(databaseName);
-    }
-
-    public MongoClient getClient() {
-        return client;
-    }
-
-    public MongoDatabase getDatabase() {
-        return database;
-    }
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/MongoDocument.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/MongoDocument.java
deleted file mode 100644
index f41de08..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/MongoDocument.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.billing.azure;
-
-import com.epam.dlab.exceptions.DlabException;
-import org.bson.Document;
-
-import java.lang.reflect.Field;
-
-public abstract class MongoDocument<T> {
-
-    protected Document to() {
-        Field[] fields = this.getClass().getDeclaredFields();
-        Document document = new Document();
-
-        try {
-            for (Field field : fields) {
-                field.setAccessible(true);
-                if (field.getType().isEnum()) {
-                    document.append(field.getName(), field.get(this).toString());
-                } else {
-                    document.append(field.getName(), field.get(this));
-                }
-            }
-
-            return document;
-
-        } catch (IllegalArgumentException | IllegalAccessException e) {
-            throw new DlabException("", e);
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    private T from(Document document) {
-
-        Field[] fields = this.getClass().getDeclaredFields();
-
-        try {
-            for (Field field : fields) {
-                field.setAccessible(true);
-
-                if (field.getType().isEnum()) {
-                    field.set(this, Enum.valueOf((Class<Enum>) field.getType(), (String) document.get(field.getName())));
-                } else {
-                    field.set(this, document.get(field.getName()));
-                }
-            }
-            return (T) this;
-        } catch (IllegalArgumentException | IllegalAccessException e) {
-            throw new DlabException("", e);
-        }
-    }
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/config/AggregationOutputMongoDataSource.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/config/AggregationOutputMongoDataSource.java
deleted file mode 100644
index 345586d..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/config/AggregationOutputMongoDataSource.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.billing.azure.config;
-
-import lombok.Data;
-
-@Data
-public class AggregationOutputMongoDataSource {
-    private String host;
-    private int port;
-    private String username;
-    private String password;
-    private String database;
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/config/BillingConfigurationAzure.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/config/BillingConfigurationAzure.java
deleted file mode 100644
index 0a28828..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/config/BillingConfigurationAzure.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.billing.azure.config;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-@ConfigurationProperties("dlab")
-@Data
-public class BillingConfigurationAzure {
-    private String sbn;
-    private long initialDelay;
-    private long period;
-
-    private String clientId;
-    private String clientSecret;
-    private String tenantId;
-    private String subscriptionId;
-
-    private String authenticationFile;
-
-    private String offerNumber;
-    private String currency;
-    private String locale;
-    private String regionInfo;
-    private boolean billingEnabled;
-
-    private String ssnStorageAccountTagName;
-    private String sharedStorageAccountTagName;
-    private String datalakeTagName;
-
-    private AggregationOutputMongoDataSource aggregationOutputMongoDataSource;
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/config/LoggingConfigurationFactory.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/config/LoggingConfigurationFactory.java
deleted file mode 100644
index 0c34a0d..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/config/LoggingConfigurationFactory.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * 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.billing.azure.config;
-
-import ch.qos.logback.classic.Level;
-import ch.qos.logback.classic.Logger;
-import ch.qos.logback.classic.LoggerContext;
-import com.epam.dlab.billing.azure.logging.AppenderBase;
-import com.epam.dlab.exceptions.InitializationException;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import org.slf4j.LoggerFactory;
-
-/**
- * Configuration and factory for logging.
- */
-public class LoggingConfigurationFactory {
-
-	/**
-	 * Default logging level for all appenders.
-	 */
-	@JsonProperty
-	private Level level = Level.INFO;
-
-	/**
-	 * List of logging levels for appenders.
-	 */
-	@JsonIgnore
-	private ImmutableMap<String, Level> loggers = ImmutableMap.of();
-
-	/**
-	 * List of logging appenders.
-	 */
-	@JsonProperty
-	private ImmutableList<AppenderBase> appenders = ImmutableList.of();
-
-
-	/**
-	 * Return the default logging level for all appenders.
-	 */
-	public Level getLevel() {
-		return level;
-	}
-
-	/**
-	 * Set the default logging level for all appenders.
-	 */
-	public void setLevel(String level) throws InitializationException {
-		this.level = toLevel(level);
-	}
-
-	/**
-	 * Return the list of logging levels for appenders.
-	 */
-	public ImmutableMap<String, Level> getLoggers() {
-		return loggers;
-	}
-
-	/**
-	 * Set the list of logging levels for appenders.
-	 */
-	@JsonProperty
-	public void setLoggers(ImmutableMap<String, JsonNode> loggers) throws InitializationException {
-		ImmutableMap.Builder<String, Level> levels = new ImmutableMap.Builder<>();
-		for (String key : loggers.keySet()) {
-			JsonNode node = loggers.get(key);
-			levels.put(key, toLevel(node.asText()));
-		}
-		this.loggers = levels.build();
-	}
-
-	/**
-	 * Return the list of logging appenders.
-	 */
-	public ImmutableList<AppenderBase> getAppenders() {
-		return appenders;
-	}
-
-	/**
-	 * Set the list of logging appenders.
-	 */
-	public void setAppenders(ImmutableList<AppenderBase> appenders) {
-		this.appenders = appenders;
-	}
-
-
-	/**
-	 * Translate the name of logging level to {@link Level}.
-	 *
-	 * @param level the name of logging level.
-	 * @return logging level.
-	 * @throws InitializationException if given unknown logging level name.
-	 */
-	private Level toLevel(String level) throws InitializationException {
-		Level l = Level.toLevel(level, null);
-		if (l == null) {
-			throw new InitializationException("Unknown logging level: " + level);
-		}
-		return l;
-	}
-
-	/**
-	 * Configure logging appenders.
-	 *
-	 * @throws InitializationException
-	 */
-	public void configure() throws InitializationException {
-		if (appenders == null) {
-			throw new InitializationException("Configuration property logging.appenders cannot be null.");
-		}
-		LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
-		context.reset();
-
-		for (AppenderBase appender : appenders) {
-			appender.configure(context);
-		}
-
-		Logger logger = context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
-		logger.setLevel(level);
-		for (String name : loggers.keySet()) {
-			logger = context.getLogger(name);
-			logger.setLevel(loggers.get(name));
-		}
-	}
-
-
-	/**
-	 * Returns a string representation of the object.
-	 *
-	 * @param self the object to generate the string for (typically this), used only for its class name.
-	 */
-	public ToStringHelper toStringHelper(Object self) {
-		return MoreObjects.toStringHelper(self)
-				.add("level", level)
-				.add("loggers", loggers)
-				.add("appenders", appenders);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this)
-				.toString();
-	}
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/config/SecurityConfig.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/config/SecurityConfig.java
deleted file mode 100644
index 9ee3d0a..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/config/SecurityConfig.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.billing.azure.config;
-
-import org.keycloak.adapters.KeycloakConfigResolver;
-import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
-import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
-import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
-import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
-import org.springframework.security.core.session.SessionRegistryImpl;
-import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
-import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
-
-@KeycloakConfiguration
-class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
-
-    @Autowired
-    public void configureGlobal(AuthenticationManagerBuilder auth) {
-        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
-        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
-        auth.authenticationProvider(keycloakAuthenticationProvider);
-    }
-
-    @Bean
-    public KeycloakConfigResolver keycloakConfigResolver() {
-        return new KeycloakSpringBootConfigResolver();
-    }
-
-    @Bean
-    @Override
-    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
-        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
-    }
-
-    @Override
-    protected void configure(HttpSecurity http) throws Exception {
-        super.configure(http);
-        http
-                .anonymous().disable()
-                .authorizeRequests()
-                .anyRequest()
-                .authenticated();
-    }
-}
\ No newline at end of file
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/controller/BillingController.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/controller/BillingController.java
deleted file mode 100644
index 9018791..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/controller/BillingController.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.billing.azure.controller;
-
-import com.epam.dlab.billing.azure.CalculateBillingService;
-import com.epam.dlab.dto.billing.BillingData;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.List;
-
-@RestController
-public class BillingController {
-
-    private final CalculateBillingService billingService;
-
-    public BillingController(CalculateBillingService billingService) {
-        this.billingService = billingService;
-    }
-
-    @GetMapping
-    public ResponseEntity<List<BillingData>> getBilling() {
-        return new ResponseEntity<>(billingService.getBillingData(), HttpStatus.OK);
-    }
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/logging/AppenderBase.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/logging/AppenderBase.java
deleted file mode 100644
index 405b56b..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/logging/AppenderBase.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.billing.azure.logging;
-
-import ch.qos.logback.classic.Logger;
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.OutputStreamAppender;
-import com.epam.dlab.exceptions.InitializationException;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import java.util.TimeZone;
-
-/** Abstract class provides base configuration for the log appenders.
- */
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
-public abstract class AppenderBase {
-
-	/** Log format pattern. */
-	private final String logFormatPattern = "%-5p [%d{ISO8601," + TimeZone.getDefault().getID() + "}] %c: %m%n%rEx";
-	
-	/** Perform configure of appender.
-	 * @param context the context of logger.
-	 */
-	public abstract void configure(LoggerContext context) throws InitializationException;
-	
-	/** Perform the base configure of appender.
-	 * @param context the context of logger.
-	 * @param appenderName the name of appender.
-	 * @param appender the class instance of appender.
-	 */
-	public void configure(LoggerContext context, String appenderName, OutputStreamAppender<ILoggingEvent> appender) {
-        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
-        encoder.setPattern(logFormatPattern);
-        encoder.setContext(context);
-        encoder.start();
-
-        appender.setContext(context);
-        appender.setName(appenderName);
-        appender.setEncoder(encoder);
-        appender.start();
-
-        Logger logger = context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
-        logger.addAppender(appender);
-        logger.setAdditive(true);
-	}
-
-	/** Return the name of type for appender. */
-	@JsonIgnore
-	public String getType() {
-		Class<? extends AppenderBase> clazz = this.getClass();
-		return (clazz.isAnnotationPresent(JsonTypeName.class) ?
-				clazz.getAnnotation(JsonTypeName.class).value() : clazz.getName());
-	}
-	
-	
-	/** Returns a string representation of the object.
-	 * @param self the object to generate the string for (typically this), used only for its class name.
-	 */
-	public ToStringHelper toStringHelper(Object self) {
-    	return MoreObjects.toStringHelper(self)
-    			.add("type",  getType());
-    }
-    
-    @Override
-    public String toString() {
-    	return toStringHelper(this)
-    			.toString();
-    }
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/logging/AppenderConsole.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/logging/AppenderConsole.java
deleted file mode 100644
index 262e414..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/logging/AppenderConsole.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.billing.azure.logging;
-
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.ConsoleAppender;
-import com.epam.dlab.exceptions.InitializationException;
-import com.fasterxml.jackson.annotation.JsonClassDescription;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-
-/** Console appender for logging.
- */
-@JsonTypeName("console")
-@JsonClassDescription(
-	"Console log appender.\n" +
-	"Output log data to console. Does not have any properties.\n" +
-	"  - type: console"
-	)
-public class AppenderConsole extends AppenderBase {
-	
-	@Override
-    public void configure(LoggerContext context)  throws InitializationException {
-    	super.configure(context, "console-appender", new ConsoleAppender<ILoggingEvent>());
-    }
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/logging/AppenderFile.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/logging/AppenderFile.java
deleted file mode 100644
index 28c14f8..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/logging/AppenderFile.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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.billing.azure.logging;
-
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.CoreConstants;
-import ch.qos.logback.core.FileAppender;
-import ch.qos.logback.core.rolling.DefaultTimeBasedFileNamingAndTriggeringPolicy;
-import ch.qos.logback.core.rolling.RollingFileAppender;
-import ch.qos.logback.core.rolling.TimeBasedFileNamingAndTriggeringPolicy;
-import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
-import com.epam.dlab.exceptions.InitializationException;
-import com.fasterxml.jackson.annotation.JsonClassDescription;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeName;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-/** File appender for logging. Support rolling files and archiving.
- */
-@JsonTypeName("file")
-@JsonClassDescription(
-	"File log appender.\n" + 
-	"Output log data to the file, if property archive is set to true then rolling\n" +
-	"mode is enabled. If archivedLogFilenamePattern ends with .gz or .zip extension\n" +
-	"then old log file will be compressed.\n" +
-	"  - type: file\n" +
-	"    currentLogFilename: <[path/]filename.log>  - pattern for log file naming.\n" +
-	"    [archive: <true | false>]                  - rolling log files or none.\n" +
-	"    [archivedLogFilenamePattern: <[path/]filename-%d{yyyy-MM-dd}.log[.gz | .zip]>]\n" +
-	"                                               - pattern for naming the archive log\n" +
-	"                                                 files.\n" +
-	"    [archivedFileCount: <number_of_days>]      - number of archive log file history."
-	)
-public class AppenderFile extends AppenderBase {
-
-	/** The name of current log file. */
-    @JsonProperty
-    private String currentLogFilename;
-
-	/** Flag for archive of old files. */
-    @JsonProperty
-    private boolean archive = false;
-    
-    /** Pattern for naming archive files. The compression mode depending on last
-	 * letters of the fileNamePatternStr. Patterns ending with .gz imply GZIP
-	 * compression, endings with '.zip' imply ZIP compression. Otherwise and by
-	 * default, there is no compression. */
-    @JsonProperty
-    private String archivedLogFilenamePattern;
-    
-    /** The maximum number of archive files to keep.. */
-    @JsonProperty
-    private int archivedFileCount = CoreConstants.UNBOUND_HISTORY;
-    
-    
-    /** Return the name of current log file. */
-    public String getCurrentLogFilename() {
-    	return currentLogFilename;
-    }
-    
-    /** Set the name of current log file. */
-    public void setCurrentLogFilename(String currentLogFilename) {
-    	this.currentLogFilename = currentLogFilename;
-    }
-    
-    /** Return the flag for archive of old files. */
-    public boolean getArchive() {
-    	return archive;
-    }
-    
-    /** Set the flag for archive of old files. */
-    public void setArchive(boolean archive) {
-    	this.archive = archive;
-    }
-    
-    /** Return the pattern for naming archive files. */
-    public String getArchivedLogFilenamePattern() {
-    	return archivedLogFilenamePattern;
-    }
-    
-    /** Set pattern for naming archive files. The compression mode depending on last
-	 * letters of the fileNamePatternStr. Patterns ending with .gz imply GZIP
-	 * compression, endings with '.zip' imply ZIP compression. Otherwise and by
-	 * default, there is no compression.
-	 * For example,
-	 * /logs/application-%d{yyyy-MM-dd}.log.gz
-	 */
-    public void setArchivedLogFilenamePattern(String archivedLogFilenamePattern) {
-    	this.archivedLogFilenamePattern = archivedLogFilenamePattern;
-    }
-    
-    /** Return the maximum number of archive files to keep.. */
-    public int getArchivedFileCount() {
-    	return archivedFileCount;
-    }
-    
-    /** Set the maximum number of archive files to keep.. */
-    public void setArchivedFileCount(int archivedFileCount) {
-    	this.archivedFileCount = archivedFileCount;
-    }
-    
-    
-    @Override
-    public void configure(LoggerContext context) throws InitializationException {
-    	if (currentLogFilename == null || currentLogFilename.trim().isEmpty()) {
-    		throw new InitializationException("Configuration property logging.appenders.currentLogFilename cannot be null.");
-    	}
-    	super.configure(context, "file-appender", (archive ? getRollingFileAppender(context) : getFileAppender()));
-    }
-
-    /** Create and return synchronous the file appender. 
-     */
-	private FileAppender<ILoggingEvent> getFileAppender() {
-		FileAppender<ILoggingEvent> appender = new FileAppender<>();
-		appender.setFile(currentLogFilename);
-		appender.setAppend(true);
-		return appender;
-	}
-	
-    /** Create and return synchronous the rolling file appender.
-     * @param context the context of logger. 
-     */
-	private RollingFileAppender<ILoggingEvent> getRollingFileAppender(LoggerContext context) throws InitializationException {
-		if (archivedLogFilenamePattern == null || archivedLogFilenamePattern.trim().isEmpty()) {
-			throw new InitializationException("Configuration property logging.appenders.archivedLogFilenamePattern cannot be null.");
-		}
-		RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();
-		appender.setFile(currentLogFilename);
-		appender.setAppend(true);
-
-		TimeBasedFileNamingAndTriggeringPolicy<ILoggingEvent> triggerPolicy = new DefaultTimeBasedFileNamingAndTriggeringPolicy<>();
-		triggerPolicy.setContext(context);
-
-		TimeBasedRollingPolicy<ILoggingEvent> rollPolicy = new TimeBasedRollingPolicy<>();
-		rollPolicy.setContext(context);
-		rollPolicy.setParent(appender);
-		rollPolicy.setFileNamePattern(archivedLogFilenamePattern);
-        rollPolicy.setMaxHistory(archivedFileCount);
-        rollPolicy.setTimeBasedFileNamingAndTriggeringPolicy(triggerPolicy);
-        rollPolicy.start();
-        appender.setRollingPolicy(rollPolicy);
-        
-		return appender;
-	}
-
-	
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("currentLogFilename", currentLogFilename)
-				.add("archive", archive)
-				.add("archivedLogFilenamePattern", archivedLogFilenamePattern)
-				.add("archivedFileCount", archivedFileCount);
-	}
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/model/AzureDailyResourceInvoice.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/model/AzureDailyResourceInvoice.java
deleted file mode 100644
index 486ddd5..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/model/AzureDailyResourceInvoice.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.billing.azure.model;
-
-import com.epam.dlab.billing.azure.MongoDocument;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-@Data
-@Builder
-@EqualsAndHashCode(callSuper = true)
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class AzureDailyResourceInvoice extends MongoDocument<AzureDailyResourceInvoice> {
-	@JsonProperty
-	private String dlabId;
-	@JsonProperty
-	private String meterCategory;
-	@JsonProperty
-	private String usageStartDate;
-	@JsonProperty
-	private String usageEndDate;
-	@JsonProperty
-	private String day;
-	@JsonProperty
-	private double cost;
-	@JsonProperty
-	private String currencyCode;
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/model/AzureDlabBillableResource.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/model/AzureDlabBillableResource.java
deleted file mode 100644
index 639788b..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/model/AzureDlabBillableResource.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.billing.azure.model;
-
-import com.epam.dlab.billing.DlabResourceType;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
-@Builder
-public class AzureDlabBillableResource {
-    private String id;
-    private DlabResourceType type;
-    private String user;
-    private String project;
-    private String notebookId;
-    private String resourceName;
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/model/BillingPeriod.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/model/BillingPeriod.java
deleted file mode 100644
index e4a8647..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/model/BillingPeriod.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.billing.azure.model;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.util.Date;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class BillingPeriod {
-    @JsonProperty
-    private Date from;
-    @JsonProperty
-    private Date to;
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/rate/AzureRateCardClient.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/rate/AzureRateCardClient.java
deleted file mode 100644
index 39e2ec1..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/rate/AzureRateCardClient.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.billing.azure.rate;
-
-import com.epam.dlab.billing.azure.config.BillingConfigurationAzure;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.http.*;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.utils.URIBuilder;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.DefaultRedirectStrategy;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.protocol.HttpContext;
-import org.apache.http.util.EntityUtils;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.function.Predicate;
-
-@Slf4j
-public class AzureRateCardClient {
-	private ObjectMapper objectMapper = new ObjectMapper();
-	public static final String MAIN_RATE_KEY = "0";
-	private BillingConfigurationAzure billingConfigurationAzure;
-	private String authToken;
-
-	public AzureRateCardClient(BillingConfigurationAzure billingConfigurationAzure, String authToken) {
-		this.billingConfigurationAzure = billingConfigurationAzure;
-		this.authToken = authToken;
-	}
-
-	public RateCardResponse getRateCard() throws IOException, URISyntaxException {
-
-		try (CloseableHttpClient httpClient = HttpClients.custom()
-				.setRedirectStrategy(new CustomRedirectWithoutAuthorizationStrategy())
-				.build()) {
-			final URIBuilder uriBuilder = new URIBuilder("https://management.azure.com/subscriptions/" +
-					billingConfigurationAzure.getSubscriptionId() + "/providers/Microsoft.Commerce/RateCard")
-					.addParameter("api-version", "2016-08-31-preview")
-					.addParameter("$filter", String.format("OfferDurableId eq '%s' and Currency eq '%s' and Locale " +
-									"eq '%s' and RegionInfo eq '%s'", billingConfigurationAzure.getOfferNumber(),
-							billingConfigurationAzure.getCurrency(), billingConfigurationAzure.getLocale(),
-							billingConfigurationAzure.getRegionInfo()));
-
-			final HttpGet request = new HttpGet(uriBuilder.build());
-			request.addHeader("Authorization", String.format("Bearer %s", authToken));
-			request.addHeader(HttpHeaders.ACCEPT, "application/json");
-			return objectMapper.readValue(EntityUtils.toString
-					(httpClient.execute(request).getEntity()), RateCardResponse.class);
-		} catch (IOException | URISyntaxException e) {
-			log.error("Cannot retrieve rate card due to ", e);
-			throw e;
-		}
-	}
-
-	class CustomRedirectWithoutAuthorizationStrategy extends DefaultRedirectStrategy {
-		@Override
-		public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws
-				ProtocolException {
-			if (HttpGet.METHOD_NAME.equals(request.getRequestLine().getMethod())) {
-				return httpGetWithoutAuthorization(request, response, context);
-			} else {
-				return super.getRedirect(request, response, context);
-			}
-		}
-
-		private HttpUriRequest httpGetWithoutAuthorization(HttpRequest request, HttpResponse response, HttpContext
-				context) throws ProtocolException {
-			return new HttpGet(getLocationURI(request, response, context)) {
-				@Override
-				public void setHeaders(Header[] headers) {
-					super.setHeaders(filter(headers, h -> !h.getName().equals(HttpHeaders.AUTHORIZATION)));
-				}
-
-				private Header[] filter(Header[] headers, Predicate<Header> predicate) {
-					return Arrays.stream(headers)
-							.filter(predicate)
-							.toArray(Header[]::new);
-				}
-			};
-		}
-	}
-
-
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/rate/Meter.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/rate/Meter.java
deleted file mode 100644
index 68cdd7f..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/rate/Meter.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.billing.azure.rate;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.util.List;
-import java.util.Map;
-
-@Data
-public class Meter {
-    @JsonProperty("EffectiveDate")
-    private String effectiveDate;
-    @JsonProperty("IncludedQuantity")
-    private long includedQuantity;
-    @JsonProperty("MeterCategory")
-    private String meterCategory;
-    @JsonProperty("MeterId")
-    private String meterId;
-    @JsonProperty("MeterName")
-    private String meterName;
-    @JsonProperty("MeterRates")
-    private Map<String, Double> meterRates;
-    @JsonProperty("MeterRegion")
-    private String meterRegion;
-    @JsonProperty("MeterStatus")
-    private String meterStatus;
-    @JsonProperty("MeterSubCategory")
-    private String meterSubCategory;
-    @JsonProperty("MeterTags")
-    private List<Object> meterTags;
-    @JsonProperty("Unit")
-    private String unit;
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/rate/RateCardResponse.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/rate/RateCardResponse.java
deleted file mode 100644
index 3797d52..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/rate/RateCardResponse.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.billing.azure.rate;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.ToString;
-
-import java.util.List;
-
-@Data
-@ToString(exclude = "meters")
-public class RateCardResponse {
-    @JsonProperty("OfferTerms")
-    private List<Object> offerTerms;
-    @JsonProperty("Meters")
-    private List<Meter> meters;
-    @JsonProperty("Currency")
-    private String currency;
-    @JsonProperty("Locale")
-    private String locale;
-    @JsonProperty("IsTaxIncluded")
-    private boolean taxIncluded;
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/AzureUsageAggregateClient.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/AzureUsageAggregateClient.java
deleted file mode 100644
index 9247d4f..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/AzureUsageAggregateClient.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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.billing.azure.usage;
-
-import com.epam.dlab.billing.azure.config.BillingConfigurationAzure;
-import com.epam.dlab.exceptions.DlabException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.http.HttpHeaders;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.utils.URIBuilder;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.util.EntityUtils;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.Objects;
-
-@Slf4j
-public class AzureUsageAggregateClient {
-	private ObjectMapper objectMapper = new ObjectMapper();
-	private BillingConfigurationAzure billingConfigurationAzure;
-	private String authToken;
-
-	public AzureUsageAggregateClient(BillingConfigurationAzure billingConfigurationAzure, String authToken) {
-		this.billingConfigurationAzure = billingConfigurationAzure;
-		this.authToken = authToken;
-	}
-
-	public UsageAggregateResponse getUsageAggregateResponse(String from, String to) throws IOException,
-			URISyntaxException {
-		try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
-
-			final URIBuilder uriBuilder = new URIBuilder("https://management.azure.com/subscriptions/" +
-					billingConfigurationAzure.getSubscriptionId() + "/providers/Microsoft" +
-					".Commerce/UsageAggregates")
-					.addParameter("api-version", "2015-06-01-preview")
-					.addParameter("reportedStartTime", from)
-					.addParameter("reportedEndTime", to)
-					.addParameter("aggregationGranularity", "daily")
-					.addParameter("showDetails", "false");
-			final HttpGet request = new HttpGet(uriBuilder.build());
-			request.addHeader("Authorization", String.format("Bearer %s", authToken));
-			request.addHeader(HttpHeaders.ACCEPT, "application/json");
-			final UsageAggregateResponse usageAggregateResponse = objectMapper.readValue(EntityUtils.toString
-					(httpClient.execute(request).getEntity()), UsageAggregateResponse.class);
-			return postProcess(usageAggregateResponse);
-		} catch (URISyntaxException e) {
-			log.error("Cannot retrieve usage detail due to ", e);
-			throw e;
-		}
-	}
-
-
-	public UsageAggregateResponse getUsageAggregateResponse(String nextUrl) throws IOException {
-		try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
-			final HttpGet request = new HttpGet(nextUrl);
-			request.addHeader("Authorization", String.format("Bearer %s", authToken));
-			request.addHeader(HttpHeaders.ACCEPT, "application/json");
-			final UsageAggregateResponse usageAggregateResponse = objectMapper.readValue(EntityUtils.toString
-					(httpClient.execute(request).getEntity()), UsageAggregateResponse.class);
-			return postProcess(usageAggregateResponse);
-		}
-	}
-
-	public void setAuthToken(String authToken) {
-		this.authToken = authToken;
-	}
-
-	private UsageAggregateResponse postProcess(UsageAggregateResponse usageAggregateResponse) {
-		usageAggregateResponse.getValue()
-				.stream()
-				.filter(r -> Objects.nonNull(r.getProperties().getInstanceData()))
-				.forEach(r -> r.getProperties().setParsedInstanceData(toInstanceData(r)));
-		return usageAggregateResponse;
-	}
-
-	private InstanceData toInstanceData(UsageAggregateRecord r) {
-		try {
-			return objectMapper.readValue(r.getProperties().getInstanceData(), InstanceData.class);
-		} catch (IOException e) {
-			throw new DlabException("Can not parse instance data", e);
-		}
-	}
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/InstanceData.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/InstanceData.java
deleted file mode 100644
index e175f2d..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/InstanceData.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.billing.azure.usage;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-@Data
-public class InstanceData {
-    @JsonProperty("Microsoft.Resources")
-    private MicrosoftResources microsoftResources;
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/MicrosoftResources.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/MicrosoftResources.java
deleted file mode 100644
index 5217efb..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/MicrosoftResources.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.billing.azure.usage;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.util.Map;
-
-@Data
-public class MicrosoftResources {
-    @JsonProperty
-    private String resourceUri;
-    @JsonProperty
-    private String location;
-    @JsonProperty
-    private Map<String, String> tags;
-    @JsonProperty
-    private Map<String, String> additionalInfo;
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/UsageAggregateRecord.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/UsageAggregateRecord.java
deleted file mode 100644
index 95f8e87..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/UsageAggregateRecord.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.billing.azure.usage;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-@Data
-public class UsageAggregateRecord {
-    @JsonProperty
-    private String id;
-    @JsonProperty
-    private String name;
-    @JsonProperty
-    private String type;
-    @JsonProperty
-    private UsageAggregateRecordProperties properties;
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/UsageAggregateRecordProperties.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/UsageAggregateRecordProperties.java
deleted file mode 100644
index d0a986e..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/UsageAggregateRecordProperties.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.billing.azure.usage;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.util.Map;
-
-@Data
-public class UsageAggregateRecordProperties {
-    @JsonProperty
-    private String subscriptionId;
-    @JsonProperty
-    private String usageStartTime;
-    @JsonProperty
-    private String usageEndTime;
-    @JsonProperty
-    private String meterName;
-    @JsonProperty
-    private String meterRegion;
-    @JsonProperty
-    private String meterCategory;
-    @JsonProperty
-    private String meterSubCategory;
-    @JsonProperty
-    private String unit;
-    @JsonProperty
-    private String instanceData;
-    private InstanceData parsedInstanceData;
-    @JsonProperty
-    private String meterId;
-    @JsonProperty
-    private Map<String, String> infoFields;
-    @JsonProperty
-    private double quantity;
-}
diff --git a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/UsageAggregateResponse.java b/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/UsageAggregateResponse.java
deleted file mode 100644
index be9078b..0000000
--- a/services/billing-azure/src/main/java/com/epam/dlab/billing/azure/usage/UsageAggregateResponse.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.billing.azure.usage;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class UsageAggregateResponse {
-    @JsonProperty
-    private List<UsageAggregateRecord> value;
-    @JsonProperty
-    private String nextLink;
-}
diff --git a/services/billing-azure/src/main/resources/application.yml b/services/billing-azure/src/main/resources/application.yml
index f029e30..60527a3 100644
--- a/services/billing-azure/src/main/resources/application.yml
+++ b/services/billing-azure/src/main/resources/application.yml
@@ -26,7 +26,7 @@
     mongodb:
       username: admin
       password: admin
-      database: dlabdb
+      database: datalabdb
       port: 27017
       host: localhost
 
@@ -36,25 +36,25 @@
     contextPath: /api/billing
 
 server.ssl.key-store-type: JKS
-server.ssl.key-store: /Users/ofuks/keys/dlabcert/billing.jks
+server.ssl.key-store: /home/OS_USER/keys/endpoint.keystore.jks
 server.ssl.key-store-password: KEYSTORE_PASSWORD
 server.ssl.key-alias: billing
 
 logging:
-  file: /var/opt/dlab/log/ssn/billing.log
+  file: /var/opt/datalab/log/ssn/billing.log
   level:
     com:
       epam: trace
 
 keycloak:
   bearer-only: true
-  realm: DLAB_bhliva
-  resource: sss
-  credentials.secret: cf5a484b-039b-4161-8707-ad65c0f25962
+  realm: datalab
+  resource: KEYCLOAK_CLIENT_ID
+  credentials.secret: CLIENT_SECRET
   ssl-required: none
-  auth-server-url: http://52.11.45.11:8080/auth
+  auth-server-url: KEYCLOAK_AUTH_SERVER_URL
 
-dlab:
+datalab:
   sbn: <CONF_SERVICE_BASE_NAME>
   billingEnabled: true
   clientId: <CLIENT_ID>
@@ -74,7 +74,7 @@
     port: 27017
     username: admin
     password: <MONGODB_PASSWORD>
-    database: dlabdb
+    database: datalabdb
   ssnStorageAccountTagName: <AZURE_SSN_STORAGE_ACCOUNT_TAG>
   sharedStorageAccountTagName: <AZURE_SHARED_STORAGE_ACCOUNT_TAG>
   datalakeTagName: <AZURE_DATALAKE_TAG>
\ No newline at end of file
diff --git a/services/billing-gcp/billing.yml b/services/billing-gcp/billing.yml
index 621c9b4..b3545e3 100644
--- a/services/billing-gcp/billing.yml
+++ b/services/billing-gcp/billing.yml
@@ -26,10 +26,10 @@
     mongodb:
       username: admin
       password: MONGO_PASSWORD
-      database: dlabdb
+      database: datalabdb
       port: 27017
       host: MONGO_HOST
-dlab:
+datalab:
   sbn: SERVICE_BASE_NAME
   bigQueryDataset: DATASET_NAME
   cron: 0 0 * * * *
@@ -45,14 +45,14 @@
 server.ssl.key-alias: ssn
 
 logging:
-  file: /var/opt/dlab/log/ssn/billing.log
+  file: /var/opt/datalab/log/ssn/billing.log
   level:
     com:
       epam: trace
 
 keycloak:
   bearer-only: true
-  realm: dlab
+  realm: datalab
   resource: KEYCLOAK_CLIENT_ID
   credentials.secret: KEYCLOAK_CLIENT_SECRET
   ssl-required: none
diff --git a/services/billing-gcp/pom.xml b/services/billing-gcp/pom.xml
index 43dff3b..fa4bbcf 100644
--- a/services/billing-gcp/pom.xml
+++ b/services/billing-gcp/pom.xml
@@ -22,8 +22,8 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
-        <groupId>com.epam.dlab</groupId>
-        <artifactId>dlab</artifactId>
+        <groupId>com.epam.datalab</groupId>
+        <artifactId>datalab</artifactId>
         <version>1.0</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
@@ -94,8 +94,8 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>dlab-model</artifactId>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>datalab-model</artifactId>
             <version>${project.parent.version}</version>
         </dependency>
         <dependency>
diff --git a/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/BillingGcpApplication.java b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/BillingGcpApplication.java
new file mode 100644
index 0000000..2fb7f80
--- /dev/null
+++ b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/BillingGcpApplication.java
@@ -0,0 +1,36 @@
+/*
+ * 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.datalab.billing.gcp;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+
+@SpringBootApplication
+@EnableMongoRepositories
+@EnableConfigurationProperties
+public class BillingGcpApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(BillingGcpApplication.class, args);
+    }
+
+}
diff --git a/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/conf/BillingApplicationConfiguration.java b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/conf/BillingApplicationConfiguration.java
new file mode 100644
index 0000000..ab00e5f
--- /dev/null
+++ b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/conf/BillingApplicationConfiguration.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab.billing.gcp.conf;
+
+import com.google.cloud.bigquery.BigQuery;
+import com.google.cloud.bigquery.BigQueryOptions;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class BillingApplicationConfiguration {
+
+    @Bean
+    public BigQuery bigQueryService() {
+        return BigQueryOptions.getDefaultInstance().getService();
+    }
+}
diff --git a/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/conf/DatalabConfiguration.java b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/conf/DatalabConfiguration.java
new file mode 100644
index 0000000..766e842
--- /dev/null
+++ b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/conf/DatalabConfiguration.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.billing.gcp.conf;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties("datalab")
+@Data
+public class DatalabConfiguration {
+
+    private String sbn;
+    private String bigQueryDataset;
+    private String bigQueryTable;
+    private String cron;
+}
diff --git a/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/conf/SecurityConfig.java b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/conf/SecurityConfig.java
new file mode 100644
index 0000000..2027ff8
--- /dev/null
+++ b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/conf/SecurityConfig.java
@@ -0,0 +1,66 @@
+/*
+ * 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.datalab.billing.gcp.conf;
+
+import org.keycloak.adapters.KeycloakConfigResolver;
+import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
+import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
+import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
+import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
+import org.springframework.security.core.session.SessionRegistryImpl;
+import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
+import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
+
+@KeycloakConfiguration
+class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
+
+    @Autowired
+    public void configureGlobal(AuthenticationManagerBuilder auth) {
+        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
+        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
+        auth.authenticationProvider(keycloakAuthenticationProvider);
+    }
+
+    @Bean
+    public KeycloakConfigResolver keycloakConfigResolver() {
+        return new KeycloakSpringBootConfigResolver();
+    }
+
+    @Bean
+    @Override
+    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
+        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
+    }
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        super.configure(http);
+        http
+                .anonymous().disable()
+                .authorizeRequests()
+                .anyRequest()
+                .authenticated();
+    }
+}
\ No newline at end of file
diff --git a/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/controller/BillingController.java b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/controller/BillingController.java
new file mode 100644
index 0000000..de1c322
--- /dev/null
+++ b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/controller/BillingController.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.billing.gcp.controller;
+
+import com.epam.datalab.billing.gcp.service.BillingService;
+import com.epam.datalab.dto.billing.BillingData;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+public class BillingController {
+
+    private final BillingService billingService;
+
+    public BillingController(BillingService billingService) {
+        this.billingService = billingService;
+    }
+
+    @GetMapping
+    public ResponseEntity<List<BillingData>> getBilling() {
+        return new ResponseEntity<>(billingService.getBillingData(), HttpStatus.OK);
+    }
+}
diff --git a/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/dao/BillingDAO.java b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/dao/BillingDAO.java
new file mode 100644
index 0000000..c0f484d
--- /dev/null
+++ b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/dao/BillingDAO.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab.billing.gcp.dao;
+
+import com.epam.datalab.dto.billing.BillingData;
+
+import java.util.List;
+
+@FunctionalInterface
+public interface BillingDAO {
+    List<BillingData> getBillingData() throws InterruptedException;
+}
diff --git a/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/dao/impl/BigQueryBillingDAO.java b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/dao/impl/BigQueryBillingDAO.java
new file mode 100644
index 0000000..2a05bbe
--- /dev/null
+++ b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/dao/impl/BigQueryBillingDAO.java
@@ -0,0 +1,131 @@
+/*
+ * 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.datalab.billing.gcp.dao.impl;
+
+import com.epam.datalab.billing.gcp.conf.DatalabConfiguration;
+import com.epam.datalab.billing.gcp.dao.BillingDAO;
+import com.epam.datalab.billing.gcp.model.BillingHistory;
+import com.epam.datalab.billing.gcp.repository.BillingHistoryRepository;
+import com.epam.datalab.dto.billing.BillingData;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.cloud.bigquery.BigQuery;
+import com.google.cloud.bigquery.FieldValueList;
+import com.google.cloud.bigquery.QueryJobConfiguration;
+import com.google.cloud.bigquery.QueryParameterValue;
+import com.google.cloud.bigquery.Table;
+import com.google.cloud.bigquery.TableInfo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+@Component
+@Slf4j
+public class BigQueryBillingDAO implements BillingDAO {
+    private static final String DATE_FORMAT = "yyyy-MM-dd";
+    private static final String SBN_PARAM = "sbn";
+    private static final String DATASET_PARAM = "dataset";
+
+    private final BillingHistoryRepository billingHistoryRepo;
+    private final BigQuery service;
+    private final String dataset;
+    private final String sbn;
+
+    private static final String GET_BILLING_DATA_QUERY = "SELECT b.sku.description usageType," +
+            "TIMESTAMP_TRUNC(usage_start_time, DAY, 'UTC') usage_date_from, TIMESTAMP_TRUNC(usage_end_time, DAY, " +
+            "'UTC')" +
+            " usage_date_to, sum(b.cost) cost, b.service.description product, label.value, currency\n" +
+            "FROM `%s` b\n" +
+            "CROSS JOIN UNNEST(b.labels) as label\n" +
+            "where label.key = 'name' and cost != 0 and label.value like @sbn\n" +
+            "group by usageType, usage_date_from, usage_date_to, product, value, currency";
+
+    @Autowired
+    public BigQueryBillingDAO(DatalabConfiguration conf, BillingHistoryRepository billingHistoryRepo,
+                              BigQuery service) {
+        dataset = conf.getBigQueryDataset();
+        this.service = service;
+        this.billingHistoryRepo = billingHistoryRepo;
+        sbn = conf.getSbn();
+    }
+
+    @Override
+    public List<BillingData> getBillingData() {
+        final Map<String, Long> processedBillingTables = billingHistoryRepo.findAll()
+                .stream()
+                .collect(Collectors.toMap(BillingHistory::getTableName, BillingHistory::getLastModified));
+        log.debug("Already processed billing data: {}", processedBillingTables);
+
+        return StreamSupport.stream(service.listTables(dataset).iterateAll().spliterator(), false)
+                .map(TableInfo::getTableId)
+                .map(service::getTable)
+                .filter(t -> processedBillingTables.getOrDefault(t.getTableId().getTable(), 0L) < t.getLastModifiedTime())
+                .peek(t -> log.info("Processing table {}", t.getTableId().getTable()))
+                .flatMap(this::bigQueryResultSetStream)
+                .collect(Collectors.toList());
+    }
+
+    private Stream<? extends BillingData> bigQueryResultSetStream(Table table) {
+        try {
+            final String tableName = table.getTableId().getTable();
+            final String tableId = table.getTableId().getDataset() + "." + tableName;
+            QueryJobConfiguration queryConfig = QueryJobConfiguration
+                    .newBuilder(String.format(GET_BILLING_DATA_QUERY, tableId))
+                    .addNamedParameter(SBN_PARAM, QueryParameterValue.string(sbn + "%"))
+                    .addNamedParameter(DATASET_PARAM, QueryParameterValue.string(tableId))
+                    .build();
+            final Stream<BillingData> gcpBillingDataStream =
+                    StreamSupport.stream(service.query(queryConfig).getValues().spliterator(), false)
+                            .map(this::toGcpBillingData);
+            billingHistoryRepo.save(new BillingHistory(tableName, table.getLastModifiedTime()));
+            return gcpBillingDataStream;
+        } catch (Exception e) {
+            log.error("Can not get billing info from BigQuery due to {}", e.getMessage(), e);
+            throw new DatalabException("Can not get billing info from BigQuery due to: " + e.getMessage(), e);
+        }
+    }
+
+    private BillingData toGcpBillingData(FieldValueList fields) {
+        return BillingData.builder()
+                .usageDateFrom(toLocalDate(fields, "usage_date_from"))
+                .usageDateTo(toLocalDate(fields, "usage_date_to"))
+                .cost(fields.get("cost").getNumericValue().doubleValue())
+                .product(fields.get("product").getStringValue())
+                .usageType(fields.get("usageType").getStringValue())
+                .currency(fields.get("currency").getStringValue())
+                .tag(fields.get("value").getStringValue().toLowerCase())
+                .usageDate(toLocalDate(fields, "usage_date_from").format((DateTimeFormatter.ofPattern(DATE_FORMAT))))
+                .build();
+    }
+
+    private LocalDate toLocalDate(FieldValueList fieldValues, String timestampFieldName) {
+        return LocalDate.from(Instant.ofEpochMilli(fieldValues.get(timestampFieldName).getTimestampValue() / 1000)
+                .atZone(ZoneId.systemDefault()));
+    }
+}
diff --git a/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/model/BillingHistory.java b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/model/BillingHistory.java
new file mode 100644
index 0000000..828cb0e
--- /dev/null
+++ b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/model/BillingHistory.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.datalab.billing.gcp.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+
+@Data
+@AllArgsConstructor
+public class BillingHistory {
+    @Id
+    private String tableName;
+    private final long lastModified;
+}
diff --git a/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/repository/BillingHistoryRepository.java b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/repository/BillingHistoryRepository.java
new file mode 100644
index 0000000..23cf85c
--- /dev/null
+++ b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/repository/BillingHistoryRepository.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.datalab.billing.gcp.repository;
+
+import com.epam.datalab.billing.gcp.model.BillingHistory;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public interface BillingHistoryRepository extends MongoRepository<BillingHistory, String> {
+}
diff --git a/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/service/BillingService.java b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/service/BillingService.java
new file mode 100644
index 0000000..83a44a0
--- /dev/null
+++ b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/service/BillingService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab.billing.gcp.service;
+
+import com.epam.datalab.dto.billing.BillingData;
+
+import java.util.List;
+
+@FunctionalInterface
+public interface BillingService {
+    List<BillingData> getBillingData();
+}
diff --git a/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/service/impl/BillingServiceImpl.java b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/service/impl/BillingServiceImpl.java
new file mode 100644
index 0000000..b88caba
--- /dev/null
+++ b/services/billing-gcp/src/main/java/com/epam/datalab/billing/gcp/service/impl/BillingServiceImpl.java
@@ -0,0 +1,52 @@
+/*
+ * 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.datalab.billing.gcp.service.impl;
+
+import com.epam.datalab.billing.gcp.dao.BillingDAO;
+import com.epam.datalab.billing.gcp.service.BillingService;
+import com.epam.datalab.dto.billing.BillingData;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Collections;
+import java.util.List;
+
+@Service
+@Slf4j
+public class BillingServiceImpl implements BillingService {
+
+    private final BillingDAO billingDAO;
+
+    @Autowired
+    public BillingServiceImpl(BillingDAO billingDAO) {
+        this.billingDAO = billingDAO;
+    }
+
+    @Override
+    public List<BillingData> getBillingData() {
+        try {
+            return billingDAO.getBillingData();
+        } catch (Exception e) {
+            log.error("Can not update billing due to: {}", e.getMessage(), e);
+            return Collections.emptyList();
+        }
+    }
+}
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/BillingGcpApplication.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/BillingGcpApplication.java
deleted file mode 100644
index c454038..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/BillingGcpApplication.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.billing.gcp;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
-
-@SpringBootApplication
-@EnableMongoRepositories
-@EnableConfigurationProperties
-public class BillingGcpApplication {
-
-    public static void main(String[] args) {
-        SpringApplication.run(BillingGcpApplication.class, args);
-    }
-
-}
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/conf/BillingApplicationConfiguration.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/conf/BillingApplicationConfiguration.java
deleted file mode 100644
index 79c1d9e..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/conf/BillingApplicationConfiguration.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.billing.gcp.conf;
-
-import com.google.cloud.bigquery.BigQuery;
-import com.google.cloud.bigquery.BigQueryOptions;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class BillingApplicationConfiguration {
-
-    @Bean
-    public BigQuery bigQueryService() {
-        return BigQueryOptions.getDefaultInstance().getService();
-    }
-}
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/conf/DlabConfiguration.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/conf/DlabConfiguration.java
deleted file mode 100644
index 08cff97..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/conf/DlabConfiguration.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.billing.gcp.conf;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-@ConfigurationProperties("dlab")
-@Data
-public class DlabConfiguration {
-
-    private String sbn;
-    private String bigQueryDataset;
-    private String bigQueryTable;
-    private String cron;
-}
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/conf/SecurityConfig.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/conf/SecurityConfig.java
deleted file mode 100644
index 5666283..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/conf/SecurityConfig.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.billing.gcp.conf;
-
-import org.keycloak.adapters.KeycloakConfigResolver;
-import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
-import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
-import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
-import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
-import org.springframework.security.core.session.SessionRegistryImpl;
-import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
-import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
-
-@KeycloakConfiguration
-class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
-
-    @Autowired
-    public void configureGlobal(AuthenticationManagerBuilder auth) {
-        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
-        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
-        auth.authenticationProvider(keycloakAuthenticationProvider);
-    }
-
-    @Bean
-    public KeycloakConfigResolver keycloakConfigResolver() {
-	    return new KeycloakSpringBootConfigResolver();
-    }
-
-    @Bean
-    @Override
-    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
-        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
-    }
-
-    @Override
-    protected void configure(HttpSecurity http) throws Exception {
-        super.configure(http);
-        http
-                .anonymous().disable()
-                .authorizeRequests()
-                .anyRequest()
-                .authenticated();
-    }
-}
\ No newline at end of file
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/controller/BillingController.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/controller/BillingController.java
deleted file mode 100644
index ea45d89..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/controller/BillingController.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.billing.gcp.controller;
-
-import com.epam.dlab.billing.gcp.service.BillingService;
-import com.epam.dlab.dto.billing.BillingData;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.List;
-
-@RestController
-public class BillingController {
-
-    private final BillingService billingService;
-
-    public BillingController(BillingService billingService) {
-        this.billingService = billingService;
-    }
-
-    @GetMapping
-    public ResponseEntity<List<BillingData>> getBilling() {
-        return new ResponseEntity<>(billingService.getBillingData(), HttpStatus.OK);
-    }
-}
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/dao/BillingDAO.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/dao/BillingDAO.java
deleted file mode 100644
index 31a636b..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/dao/BillingDAO.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.billing.gcp.dao;
-
-import com.epam.dlab.dto.billing.BillingData;
-
-import java.util.List;
-
-@FunctionalInterface
-public interface BillingDAO {
-	List<BillingData> getBillingData() throws InterruptedException;
-}
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/dao/impl/BigQueryBillingDAO.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/dao/impl/BigQueryBillingDAO.java
deleted file mode 100644
index 3a93429..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/dao/impl/BigQueryBillingDAO.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.billing.gcp.dao.impl;
-
-import com.epam.dlab.billing.gcp.conf.DlabConfiguration;
-import com.epam.dlab.billing.gcp.dao.BillingDAO;
-import com.epam.dlab.billing.gcp.model.BillingHistory;
-import com.epam.dlab.billing.gcp.repository.BillingHistoryRepository;
-import com.epam.dlab.dto.billing.BillingData;
-import com.epam.dlab.exceptions.DlabException;
-import com.google.cloud.bigquery.BigQuery;
-import com.google.cloud.bigquery.FieldValueList;
-import com.google.cloud.bigquery.QueryJobConfiguration;
-import com.google.cloud.bigquery.QueryParameterValue;
-import com.google.cloud.bigquery.Table;
-import com.google.cloud.bigquery.TableInfo;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-@Component
-@Slf4j
-public class BigQueryBillingDAO implements BillingDAO {
-	private static final String DATE_FORMAT = "yyyy-MM-dd";
-	private static final String SBN_PARAM = "sbn";
-	private static final String DATASET_PARAM = "dataset";
-
-	private final BillingHistoryRepository billingHistoryRepo;
-	private final BigQuery service;
-	private final String dataset;
-	private final String sbn;
-
-	private static final String GET_BILLING_DATA_QUERY = "SELECT b.sku.description usageType," +
-			"TIMESTAMP_TRUNC(usage_start_time, DAY, 'UTC') usage_date_from, TIMESTAMP_TRUNC(usage_end_time, DAY, " +
-			"'UTC')" +
-			" usage_date_to, sum(b.cost) cost, b.service.description product, label.value, currency\n" +
-			"FROM `%s` b\n" +
-			"CROSS JOIN UNNEST(b.labels) as label\n" +
-			"where label.key = 'name' and cost != 0 and label.value like @sbn\n" +
-			"group by usageType, usage_date_from, usage_date_to, product, value, currency";
-
-	@Autowired
-	public BigQueryBillingDAO(DlabConfiguration conf, BillingHistoryRepository billingHistoryRepo,
-	                          BigQuery service) {
-		dataset = conf.getBigQueryDataset();
-		this.service = service;
-		this.billingHistoryRepo = billingHistoryRepo;
-		sbn = conf.getSbn();
-	}
-
-	@Override
-	public List<BillingData> getBillingData() {
-		final Map<String, Long> processedBillingTables = billingHistoryRepo.findAll()
-				.stream()
-				.collect(Collectors.toMap(BillingHistory::getTableName, BillingHistory::getLastModified));
-		log.debug("Already processed billing data: {}", processedBillingTables);
-
-		return StreamSupport.stream(service.listTables(dataset).iterateAll().spliterator(), false)
-				.map(TableInfo::getTableId)
-				.map(service::getTable)
-				.filter(t -> processedBillingTables.getOrDefault(t.getTableId().getTable(), 0L) < t.getLastModifiedTime())
-				.peek(t -> log.info("Processing table {}", t.getTableId().getTable()))
-				.flatMap(this::bigQueryResultSetStream)
-				.collect(Collectors.toList());
-	}
-
-	private Stream<? extends BillingData> bigQueryResultSetStream(Table table) {
-		try {
-			final String tableName = table.getTableId().getTable();
-			final String tableId = table.getTableId().getDataset() + "." + tableName;
-			QueryJobConfiguration queryConfig = QueryJobConfiguration
-					.newBuilder(String.format(GET_BILLING_DATA_QUERY, tableId))
-					.addNamedParameter(SBN_PARAM, QueryParameterValue.string(sbn + "%"))
-					.addNamedParameter(DATASET_PARAM, QueryParameterValue.string(tableId))
-					.build();
-			final Stream<BillingData> gcpBillingDataStream =
-					StreamSupport.stream(service.query(queryConfig).getValues().spliterator(), false)
-							.map(this::toGcpBillingData);
-			billingHistoryRepo.save(new BillingHistory(tableName, table.getLastModifiedTime()));
-			return gcpBillingDataStream;
-		} catch (Exception e) {
-			log.error("Can not get billing info from BigQuery due to {}", e.getMessage(), e);
-			throw new DlabException("Can not get billing info from BigQuery due to: " + e.getMessage(), e);
-		}
-	}
-
-	private BillingData toGcpBillingData(FieldValueList fields) {
-		return BillingData.builder()
-				.usageDateFrom(toLocalDate(fields, "usage_date_from"))
-				.usageDateTo(toLocalDate(fields, "usage_date_to"))
-				.cost(fields.get("cost").getNumericValue().doubleValue())
-				.product(fields.get("product").getStringValue())
-				.usageType(fields.get("usageType").getStringValue())
-				.currency(fields.get("currency").getStringValue())
-				.tag(fields.get("value").getStringValue().toLowerCase())
-				.usageDate(toLocalDate(fields, "usage_date_from").format((DateTimeFormatter.ofPattern(DATE_FORMAT))))
-				.build();
-	}
-
-	private LocalDate toLocalDate(FieldValueList fieldValues, String timestampFieldName) {
-		return LocalDate.from(Instant.ofEpochMilli(fieldValues.get(timestampFieldName).getTimestampValue() / 1000)
-				.atZone(ZoneId.systemDefault()));
-	}
-}
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/model/BillingHistory.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/model/BillingHistory.java
deleted file mode 100644
index 8fb80f1..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/model/BillingHistory.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.billing.gcp.model;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import org.springframework.data.annotation.Id;
-
-@Data
-@AllArgsConstructor
-public class BillingHistory {
-	@Id
-	private String tableName;
-	private final long lastModified;
-}
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/model/GcpBillingData.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/model/GcpBillingData.java
deleted file mode 100644
index a2bd12b..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/model/GcpBillingData.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.billing.gcp.model;
-
-import lombok.Builder;
-import lombok.Data;
-import org.springframework.data.mongodb.core.mapping.Document;
-import org.springframework.data.mongodb.core.mapping.Field;
-
-import java.time.LocalDate;
-
-@Data
-@Builder
-@Document(collection = "billing")
-public class GcpBillingData {
-    @Field("from")
-    private final LocalDate usageDateFrom;
-    @Field("to")
-    private final LocalDate usageDateTo;
-    private final String product;
-    private final String usageType;
-    private final Double cost;
-    private final String currency;
-    @Field("dlabId")
-    private final String tag;
-    private final String usageDate;
-}
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/repository/BillingHistoryRepository.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/repository/BillingHistoryRepository.java
deleted file mode 100644
index 957ced7..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/repository/BillingHistoryRepository.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.billing.gcp.repository;
-
-import com.epam.dlab.billing.gcp.model.BillingHistory;
-import org.springframework.data.mongodb.repository.MongoRepository;
-
-public interface BillingHistoryRepository extends MongoRepository<BillingHistory, String> {
-}
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/repository/BillingRepository.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/repository/BillingRepository.java
deleted file mode 100644
index 2d4c5c1..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/repository/BillingRepository.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.billing.gcp.repository;
-
-import com.epam.dlab.billing.gcp.model.GcpBillingData;
-import org.springframework.data.mongodb.repository.MongoRepository;
-
-public interface BillingRepository extends MongoRepository<GcpBillingData, String> {
-	void deleteByUsageDateRegex(String usageDateRegex);
-}
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/service/BillingService.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/service/BillingService.java
deleted file mode 100644
index ca4277f..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/service/BillingService.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.billing.gcp.service;
-
-import com.epam.dlab.dto.billing.BillingData;
-
-import java.util.List;
-
-@FunctionalInterface
-public interface BillingService {
-	List<BillingData> getBillingData();
-}
diff --git a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/service/impl/BillingServiceImpl.java b/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/service/impl/BillingServiceImpl.java
deleted file mode 100644
index 5661dfb..0000000
--- a/services/billing-gcp/src/main/java/com/epam/dlab/billing/gcp/service/impl/BillingServiceImpl.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.billing.gcp.service.impl;
-
-import com.epam.dlab.billing.gcp.dao.BillingDAO;
-import com.epam.dlab.billing.gcp.service.BillingService;
-import com.epam.dlab.dto.billing.BillingData;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.Collections;
-import java.util.List;
-
-@Service
-@Slf4j
-public class BillingServiceImpl implements BillingService {
-
-	private final BillingDAO billingDAO;
-
-	@Autowired
-	public BillingServiceImpl(BillingDAO billingDAO) {
-		this.billingDAO = billingDAO;
-	}
-
-	@Override
-	public List<BillingData> getBillingData() {
-		try {
-			return billingDAO.getBillingData();
-		} catch (Exception e) {
-			log.error("Can not update billing due to: {}", e.getMessage(), e);
-			return Collections.emptyList();
-		}
-	}
-}
diff --git a/services/billing-gcp/src/main/resources/application.yml b/services/billing-gcp/src/main/resources/application.yml
index 9e29b04..e491cd5 100644
--- a/services/billing-gcp/src/main/resources/application.yml
+++ b/services/billing-gcp/src/main/resources/application.yml
@@ -26,10 +26,10 @@
     mongodb:
       username: admin
       password: admin
-      database: dlabdb
+      database: datalabdb
       port: 27017
       host: localhost
-dlab:
+datalab:
   sbn: <CONF_SERVICE_BASE_NAME>
   bigQueryDataset: <DATASET_NAME>
   cron: 0 0 * * * *
@@ -40,20 +40,20 @@
     contextPath: /api/billing
 
 server.ssl.key-store-type: JKS
-server.ssl.key-store: /Users/ofuks/keys/dlabcert/billing.jks
+server.ssl.key-store: /home/OS_USER/keys/endpoint.keystore.jks
 server.ssl.key-store-password: KEYSTORE_PASSWORD
 server.ssl.key-alias: billing
 
 logging:
-  file: /var/opt/dlab/log/ssn/billing.log
+  file: /var/opt/datalab/log/ssn/billing.log
   level:
     com:
       epam: trace
 
 keycloak:
   bearer-only: true
-  realm: DLAB_bhliva
-  resource: sss
-  credentials.secret: cf5a484b-039b-4161-8707-ad65c0f25962
+  realm: datalab
+  resource: KEYCLOAK_CLIENT_ID
+  credentials.secret: CLIENT_SECRET
   ssl-required: none
-  auth-server-url: http://52.11.45.11:8080/auth
\ No newline at end of file
+  auth-server-url: KEYCLOAK_AUTH_SERVER_URL
\ No newline at end of file
diff --git a/services/common/pom.xml b/services/common/pom.xml
index 1bf66dd..397a106 100644
--- a/services/common/pom.xml
+++ b/services/common/pom.xml
@@ -21,8 +21,8 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
-        <groupId>com.epam.dlab</groupId>
-        <artifactId>dlab</artifactId>
+        <groupId>com.epam.datalab</groupId>
+        <artifactId>datalab</artifactId>
         <version>1.0</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
diff --git a/services/common/src/main/java/com/epam/datalab/billing/BillingCalculationUtils.java b/services/common/src/main/java/com/epam/datalab/billing/BillingCalculationUtils.java
new file mode 100644
index 0000000..1916b2f
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/billing/BillingCalculationUtils.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.billing;
+
+public class BillingCalculationUtils {
+    private BillingCalculationUtils() {
+    }
+
+    public static String formatDouble(Double value) {
+        return (value == null ? null : String.format("%,.2f", value));
+    }
+
+    public static double round(double value, int scale) {
+        int d = (int) Math.pow(10, scale);
+        return (double) (Math.round(value * d)) / d;
+    }
+
+    public static Double round(Double value, int scale) {
+        if (value == null) {
+            return null;
+        }
+        int d = (int) Math.pow(10, scale);
+        return (double) (Math.round(value * d)) / d;
+    }
+}
diff --git a/services/common/src/main/java/com/epam/datalab/billing/DatalabResourceType.java b/services/common/src/main/java/com/epam/datalab/billing/DatalabResourceType.java
new file mode 100644
index 0000000..1b1776b
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/billing/DatalabResourceType.java
@@ -0,0 +1,54 @@
+/*
+ * 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.datalab.billing;
+
+public enum DatalabResourceType {
+    SSN,
+    SSN_BUCKET,
+    SSN_CONTAINER,
+    SSN_STORAGE_ACCOUNT,
+    DATA_LAKE_STORE,
+    COLLABORATION_BUCKET,
+    COLLABORATION_CONTAINER,
+    COLLABORATION_STORAGE_ACCOUNT,
+    EDGE,
+    EDGE_BUCKET,
+    EDGE_CONTAINER,
+    EDGE_STORAGE_ACCOUNT,
+    EXPLORATORY,
+    COMPUTATIONAL,
+    VOLUME;
+
+    public static DatalabResourceType of(String string) {
+        if (string != null) {
+            for (DatalabResourceType value : DatalabResourceType.values()) {
+                if (string.equalsIgnoreCase(value.toString())) {
+                    return value;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString().toUpperCase();
+    }
+}
diff --git a/services/common/src/main/java/com/epam/datalab/exceptions/AdapterException.java b/services/common/src/main/java/com/epam/datalab/exceptions/AdapterException.java
new file mode 100644
index 0000000..2cbea06
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/exceptions/AdapterException.java
@@ -0,0 +1,56 @@
+/*
+ * 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.datalab.exceptions;
+
+/**
+ * The exception thrown by the adapter when the connection or input/output errors acquired.
+ */
+public class AdapterException extends GenericException {
+
+    private static final long serialVersionUID = 7036318323246822560L;
+
+    /**
+     * Constructs a new exception.
+     *
+     * @param message error message.
+     */
+    public AdapterException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception.
+     *
+     * @param cause the cause.
+     */
+    public AdapterException(Exception cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a new exception.
+     *
+     * @param message error message.
+     * @param cause   the cause.
+     */
+    public AdapterException(String message, Exception cause) {
+        super(message, cause);
+    }
+}
diff --git a/services/common/src/main/java/com/epam/datalab/exceptions/DatalabAuthenticationException.java b/services/common/src/main/java/com/epam/datalab/exceptions/DatalabAuthenticationException.java
new file mode 100644
index 0000000..d48ce29
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/exceptions/DatalabAuthenticationException.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.datalab.exceptions;
+
+public class DatalabAuthenticationException extends DatalabException {
+    public DatalabAuthenticationException(String message) {
+        super(message);
+    }
+}
diff --git a/services/common/src/main/java/com/epam/datalab/exceptions/DatalabException.java b/services/common/src/main/java/com/epam/datalab/exceptions/DatalabException.java
new file mode 100644
index 0000000..15f8cb7
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/exceptions/DatalabException.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab.exceptions;
+
+public class DatalabException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    public DatalabException(String message) {
+        super(message);
+    }
+
+    public DatalabException(String message, Exception cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/services/common/src/main/java/com/epam/datalab/exceptions/DatalabValidationException.java b/services/common/src/main/java/com/epam/datalab/exceptions/DatalabValidationException.java
new file mode 100644
index 0000000..0e0abb1
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/exceptions/DatalabValidationException.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.datalab.exceptions;
+
+public class DatalabValidationException extends DatalabException {
+    public DatalabValidationException(String message) {
+        super(message);
+    }
+}
diff --git a/services/common/src/main/java/com/epam/datalab/exceptions/GenericException.java b/services/common/src/main/java/com/epam/datalab/exceptions/GenericException.java
new file mode 100644
index 0000000..b62a7bb
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/exceptions/GenericException.java
@@ -0,0 +1,56 @@
+/*
+ * 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.datalab.exceptions;
+
+/**
+ * Base abstract class for application.
+ */
+public abstract class GenericException extends Exception {
+
+    private static final long serialVersionUID = -8245773542009692611L;
+
+    /**
+     * Constructs a new exception.
+     *
+     * @param message error message.
+     */
+    public GenericException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception.
+     *
+     * @param cause the cause.
+     */
+    public GenericException(Exception cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a new exception.
+     *
+     * @param message error message.
+     * @param cause   the cause.
+     */
+    public GenericException(String message, Exception cause) {
+        super(message, cause);
+    }
+}
diff --git a/services/common/src/main/java/com/epam/datalab/exceptions/InitializationException.java b/services/common/src/main/java/com/epam/datalab/exceptions/InitializationException.java
new file mode 100644
index 0000000..a0b1e52
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/exceptions/InitializationException.java
@@ -0,0 +1,56 @@
+/*
+ * 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.datalab.exceptions;
+
+/**
+ * Exception for the error of initialization.
+ */
+public class InitializationException extends GenericException {
+
+    private static final long serialVersionUID = -666390278139508248L;
+
+    /**
+     * Constructs a new exception.
+     *
+     * @param message error message.
+     */
+    public InitializationException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception.
+     *
+     * @param cause the cause.
+     */
+    public InitializationException(Exception cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a new exception.
+     *
+     * @param message error message.
+     * @param cause   the cause.
+     */
+    public InitializationException(String message, Exception cause) {
+        super(message, cause);
+    }
+}
diff --git a/services/common/src/main/java/com/epam/datalab/exceptions/ParseException.java b/services/common/src/main/java/com/epam/datalab/exceptions/ParseException.java
new file mode 100644
index 0000000..afc45fc
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/exceptions/ParseException.java
@@ -0,0 +1,57 @@
+/*
+ * 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.datalab.exceptions;
+
+/**
+ * The exception thrown by the adapter when the convert errors acquired.
+ */
+public class ParseException extends GenericException {
+
+    private static final long serialVersionUID = -5780834425131769923L;
+
+    /**
+     * Constructs a new exception.
+     *
+     * @param message error message.
+     */
+    public ParseException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception.
+     *
+     * @param cause the cause.
+     */
+    public ParseException(Exception cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a new exception.
+     *
+     * @param message error message.
+     * @param cause   the cause.
+     */
+    public ParseException(String message, Exception cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/services/common/src/main/java/com/epam/datalab/exceptions/ResourceAlreadyExistException.java b/services/common/src/main/java/com/epam/datalab/exceptions/ResourceAlreadyExistException.java
new file mode 100644
index 0000000..f7d3d5f
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/exceptions/ResourceAlreadyExistException.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.datalab.exceptions;
+
+public class ResourceAlreadyExistException extends ResourceConflictException {
+    public ResourceAlreadyExistException(String message) {
+        super(message);
+    }
+}
diff --git a/services/common/src/main/java/com/epam/datalab/exceptions/ResourceConflictException.java b/services/common/src/main/java/com/epam/datalab/exceptions/ResourceConflictException.java
new file mode 100644
index 0000000..4e87db8
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/exceptions/ResourceConflictException.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.datalab.exceptions;
+
+public class ResourceConflictException extends DatalabException {
+    public ResourceConflictException(String message) {
+        super(message);
+    }
+}
diff --git a/services/common/src/main/java/com/epam/datalab/exceptions/ResourceInappropriateStateException.java b/services/common/src/main/java/com/epam/datalab/exceptions/ResourceInappropriateStateException.java
new file mode 100644
index 0000000..83a10f6
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/exceptions/ResourceInappropriateStateException.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.datalab.exceptions;
+
+public class ResourceInappropriateStateException extends ResourceConflictException {
+    public ResourceInappropriateStateException(String message) {
+        super(message);
+    }
+}
diff --git a/services/common/src/main/java/com/epam/datalab/exceptions/ResourceNotFoundException.java b/services/common/src/main/java/com/epam/datalab/exceptions/ResourceNotFoundException.java
new file mode 100644
index 0000000..70f001e
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/exceptions/ResourceNotFoundException.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.datalab.exceptions;
+
+public class ResourceNotFoundException extends DatalabException {
+    public ResourceNotFoundException(String message) {
+        super(message);
+    }
+}
diff --git a/services/common/src/main/java/com/epam/datalab/exceptions/ResourceQuoteReachedException.java b/services/common/src/main/java/com/epam/datalab/exceptions/ResourceQuoteReachedException.java
new file mode 100644
index 0000000..33f93d3
--- /dev/null
+++ b/services/common/src/main/java/com/epam/datalab/exceptions/ResourceQuoteReachedException.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab.exceptions;
+
+public class ResourceQuoteReachedException extends DatalabException {
+    public ResourceQuoteReachedException(String message) {
+        super(message);
+    }
+
+    public ResourceQuoteReachedException(String message, Exception cause) {
+        super(message, cause);
+    }
+}
diff --git a/services/common/src/main/java/com/epam/dlab/billing/BillingCalculationUtils.java b/services/common/src/main/java/com/epam/dlab/billing/BillingCalculationUtils.java
deleted file mode 100644
index 14edfc9..0000000
--- a/services/common/src/main/java/com/epam/dlab/billing/BillingCalculationUtils.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.billing;
-
-public class BillingCalculationUtils {
-    private BillingCalculationUtils() {
-    }
-
-    public static String formatDouble(Double value) {
-        return (value == null ? null : String.format("%,.2f", value));
-    }
-
-    public static double round(double value, int scale) {
-        int d = (int) Math.pow(10, scale);
-        return (double) (Math.round(value * d)) / d;
-    }
-
-    public static Double round(Double value, int scale) {
-        if (value == null) {
-            return null;
-        }
-        int d = (int) Math.pow(10, scale);
-        return (double) (Math.round(value * d)) / d;
-    }
-}
diff --git a/services/common/src/main/java/com/epam/dlab/billing/DlabResourceType.java b/services/common/src/main/java/com/epam/dlab/billing/DlabResourceType.java
deleted file mode 100644
index dfec0dc..0000000
--- a/services/common/src/main/java/com/epam/dlab/billing/DlabResourceType.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.billing;
-
-public enum DlabResourceType {
-	SSN,
-	SSN_BUCKET,
-	SSN_CONTAINER,
-	SSN_STORAGE_ACCOUNT,
-	DATA_LAKE_STORE,
-	COLLABORATION_BUCKET,
-	COLLABORATION_CONTAINER,
-	COLLABORATION_STORAGE_ACCOUNT,
-	EDGE,
-	EDGE_BUCKET,
-	EDGE_CONTAINER,
-	EDGE_STORAGE_ACCOUNT,
-	EXPLORATORY,
-	COMPUTATIONAL,
-	VOLUME;
-
-	public static DlabResourceType of(String string) {
-		if (string != null) {
-			for (DlabResourceType value : DlabResourceType.values()) {
-				if (string.equalsIgnoreCase(value.toString())) {
-					return value;
-				}
-			}
-		}
-		return null;
-	}
-
-	@Override
-	public String toString() {
-		return super.toString().toUpperCase();
-	}
-}
diff --git a/services/common/src/main/java/com/epam/dlab/exceptions/AdapterException.java b/services/common/src/main/java/com/epam/dlab/exceptions/AdapterException.java
deleted file mode 100644
index 1ee4ab1..0000000
--- a/services/common/src/main/java/com/epam/dlab/exceptions/AdapterException.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.exceptions;
-
-/** The exception thrown by the adapter when the connection or input/output errors acquired.
- */
-public class AdapterException extends GenericException {
-
-	private static final long serialVersionUID = 7036318323246822560L;
-
-	/** Constructs a new exception.
-	 * @param message error message.
-	 */
-	public AdapterException(String message) {
-		super(message);
-	}
-
-	/** Constructs a new exception.
-	 * @param cause the cause.
-	 */
-	public AdapterException(Exception cause) {
-		super(cause);
-	}
-
-	/** Constructs a new exception.
-	 * @param message error message.
-	 * @param cause the cause.
-	 */
-	public AdapterException(String message, Exception cause) {
-		super(message, cause);
-	}
-}
diff --git a/services/common/src/main/java/com/epam/dlab/exceptions/DlabAuthenticationException.java b/services/common/src/main/java/com/epam/dlab/exceptions/DlabAuthenticationException.java
deleted file mode 100644
index 9db3a0a..0000000
--- a/services/common/src/main/java/com/epam/dlab/exceptions/DlabAuthenticationException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.exceptions;
-
-public class DlabAuthenticationException extends DlabException {
-	public DlabAuthenticationException(String message) {
-		super(message);
-	}
-}
diff --git a/services/common/src/main/java/com/epam/dlab/exceptions/DlabException.java b/services/common/src/main/java/com/epam/dlab/exceptions/DlabException.java
deleted file mode 100644
index d6d5b6b..0000000
--- a/services/common/src/main/java/com/epam/dlab/exceptions/DlabException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.exceptions;
-
-public class DlabException extends RuntimeException {
-	
-	private static final long serialVersionUID = 1L;
-
-	public DlabException(String message) {
-        super(message);
-    }
-
-    public DlabException(String message, Exception cause) {
-        super(message, cause);
-    }
-
-}
diff --git a/services/common/src/main/java/com/epam/dlab/exceptions/DlabValidationException.java b/services/common/src/main/java/com/epam/dlab/exceptions/DlabValidationException.java
deleted file mode 100644
index f4dd287..0000000
--- a/services/common/src/main/java/com/epam/dlab/exceptions/DlabValidationException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.exceptions;
-
-public class DlabValidationException extends DlabException {
-	public DlabValidationException(String message) {
-		super(message);
-	}
-}
diff --git a/services/common/src/main/java/com/epam/dlab/exceptions/GenericException.java b/services/common/src/main/java/com/epam/dlab/exceptions/GenericException.java
deleted file mode 100644
index 677ea81..0000000
--- a/services/common/src/main/java/com/epam/dlab/exceptions/GenericException.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.exceptions;
-
-/** Base abstract class for application.  
- */
-public abstract class GenericException extends Exception {
-	
-	private static final long serialVersionUID = -8245773542009692611L;
-
-	/** Constructs a new exception.
-	 * @param message error message.
-	 */
-	public GenericException(String message) {
-		super(message);
-	}
-
-	/** Constructs a new exception.
-	 * @param cause the cause.
-	 */
-	public GenericException(Exception cause) {
-		super(cause);
-	}
-
-	/** Constructs a new exception.
-	 * @param message error message.
-	 * @param cause the cause.
-	 */
-	public GenericException(String message, Exception cause) {
-		super(message, cause);
-	}
-}
diff --git a/services/common/src/main/java/com/epam/dlab/exceptions/InitializationException.java b/services/common/src/main/java/com/epam/dlab/exceptions/InitializationException.java
deleted file mode 100644
index 0a1e8b5..0000000
--- a/services/common/src/main/java/com/epam/dlab/exceptions/InitializationException.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.exceptions;
-
-/** Exception for the error of initialization.
- */
-public class InitializationException extends GenericException {
-
-	private static final long serialVersionUID = -666390278139508248L;
-
-	/** Constructs a new exception.
-	 * @param message error message.
-	 */
-	public InitializationException(String message) {
-		super(message);
-	}
-
-	/** Constructs a new exception.
-	 * @param cause the cause.
-	 */
-	public InitializationException(Exception cause) {
-		super(cause);
-	}
-
-	/** Constructs a new exception.
-	 * @param message error message.
-	 * @param cause the cause.
-	 */
-	public InitializationException(String message, Exception cause) {
-		super(message, cause);
-	}
-}
diff --git a/services/common/src/main/java/com/epam/dlab/exceptions/ParseException.java b/services/common/src/main/java/com/epam/dlab/exceptions/ParseException.java
deleted file mode 100644
index e18d891..0000000
--- a/services/common/src/main/java/com/epam/dlab/exceptions/ParseException.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.exceptions;
-
-/** The exception thrown by the adapter when the convert errors acquired.
- */
-public class ParseException extends GenericException {
-
-	private static final long serialVersionUID = -5780834425131769923L;
-
-	/** Constructs a new exception.
-	 * @param message error message.
-	 */
-	public ParseException(String message) {
-		super(message);
-	}
-
-	/** Constructs a new exception.
-	 * @param cause the cause.
-	 */
-	public ParseException(Exception cause) {
-		super(cause);
-	}
-
-	/** Constructs a new exception.
-	 * @param message error message.
-	 * @param cause the cause.
-	 */
-	public ParseException(String message, Exception cause) {
-		super(message, cause);
-	}
-
-}
diff --git a/services/common/src/main/java/com/epam/dlab/exceptions/ResourceAlreadyExistException.java b/services/common/src/main/java/com/epam/dlab/exceptions/ResourceAlreadyExistException.java
deleted file mode 100644
index e4f8cb7..0000000
--- a/services/common/src/main/java/com/epam/dlab/exceptions/ResourceAlreadyExistException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.exceptions;
-
-public class ResourceAlreadyExistException extends ResourceConflictException {
-	public ResourceAlreadyExistException(String message) {
-		super(message);
-	}
-}
diff --git a/services/common/src/main/java/com/epam/dlab/exceptions/ResourceConflictException.java b/services/common/src/main/java/com/epam/dlab/exceptions/ResourceConflictException.java
deleted file mode 100644
index a6c7c23..0000000
--- a/services/common/src/main/java/com/epam/dlab/exceptions/ResourceConflictException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.exceptions;
-
-public class ResourceConflictException extends DlabException {
-	public ResourceConflictException(String message) {
-		super(message);
-	}
-}
diff --git a/services/common/src/main/java/com/epam/dlab/exceptions/ResourceInappropriateStateException.java b/services/common/src/main/java/com/epam/dlab/exceptions/ResourceInappropriateStateException.java
deleted file mode 100644
index 2172a0d..0000000
--- a/services/common/src/main/java/com/epam/dlab/exceptions/ResourceInappropriateStateException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.exceptions;
-
-public class ResourceInappropriateStateException extends ResourceConflictException {
-	public ResourceInappropriateStateException(String message) {
-		super(message);
-	}
-}
diff --git a/services/common/src/main/java/com/epam/dlab/exceptions/ResourceNotFoundException.java b/services/common/src/main/java/com/epam/dlab/exceptions/ResourceNotFoundException.java
deleted file mode 100644
index b5722aa..0000000
--- a/services/common/src/main/java/com/epam/dlab/exceptions/ResourceNotFoundException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.exceptions;
-
-public class ResourceNotFoundException extends DlabException {
-	public ResourceNotFoundException(String message) {
-		super(message);
-	}
-}
diff --git a/services/common/src/main/java/com/epam/dlab/exceptions/ResourceQuoteReachedException.java b/services/common/src/main/java/com/epam/dlab/exceptions/ResourceQuoteReachedException.java
deleted file mode 100644
index 3ccdf50..0000000
--- a/services/common/src/main/java/com/epam/dlab/exceptions/ResourceQuoteReachedException.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.exceptions;
-
-public class ResourceQuoteReachedException extends DlabException {
-	public ResourceQuoteReachedException(String message) {
-		super(message);
-	}
-
-	public ResourceQuoteReachedException(String message, Exception cause) {
-		super(message, cause);
-	}
-}
diff --git a/services/datalab-model/pom.xml b/services/datalab-model/pom.xml
new file mode 100644
index 0000000..2f7878a
--- /dev/null
+++ b/services/datalab-model/pom.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>datalab</artifactId>
+        <groupId>com.epam.datalab</groupId>
+        <version>1.0</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>datalab-model</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>datalab-utils</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>javax.ws.rs-api</artifactId>
+            <version>2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.validation</groupId>
+            <artifactId>validation-api</artifactId>
+            <version>2.0.0.Final</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.7</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-validator</artifactId>
+            <version>${hibernate.validator.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.dropwizard</groupId>
+            <artifactId>dropwizard-jackson</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/MongoKeyWords.java b/services/datalab-model/src/main/java/com/epam/datalab/MongoKeyWords.java
new file mode 100644
index 0000000..c226884
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/MongoKeyWords.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab;
+
+public abstract class MongoKeyWords {
+    public static final String AZURE_BILLING_SCHEDULER = "billingScheduler";
+    public static final String AZURE_BILLING_SCHEDULER_HISTORY = "billingSchedulerHistory";
+
+    /**
+     * Mongo DB keywords related to billing functionality
+     */
+    public static final String MONGO_ID = "_id";
+
+
+    private MongoKeyWords() {
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/InfrastructureMetaInfoDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/InfrastructureMetaInfoDTO.java
new file mode 100644
index 0000000..2b7f566
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/InfrastructureMetaInfoDTO.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class InfrastructureMetaInfoDTO {
+    private final String branch;
+    private final String version;
+    private final String commit;
+    @JsonProperty("release_notes")
+    private final String releaseNotes;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/LibListComputationalDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/LibListComputationalDTO.java
new file mode 100644
index 0000000..1ec78a0
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/LibListComputationalDTO.java
@@ -0,0 +1,55 @@
+/*
+ * 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.datalab.dto;
+
+import com.epam.datalab.dto.exploratory.ExploratoryActionDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString(callSuper = true)
+public class LibListComputationalDTO extends ExploratoryActionDTO<LibListComputationalDTO> {
+    @JsonProperty("computational_id")
+    private String computationalId;
+
+    @JsonProperty("computational_image")
+    private String computationalImage;
+
+    @JsonProperty
+    private String libCacheKey;
+
+    public LibListComputationalDTO withComputationalId(String computationalId) {
+        setComputationalId(computationalId);
+        return this;
+    }
+
+    public LibListComputationalDTO withComputationalImage(String computationalImage) {
+        setComputationalImage(computationalImage);
+        return this;
+    }
+
+    public LibListComputationalDTO withLibCacheKey(String libCacheKey) {
+        setLibCacheKey(libCacheKey);
+        return this;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/LibListExploratoryDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/LibListExploratoryDTO.java
new file mode 100644
index 0000000..5b71e7f
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/LibListExploratoryDTO.java
@@ -0,0 +1,40 @@
+/*
+ * 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.datalab.dto;
+
+import com.epam.datalab.dto.exploratory.ExploratoryActionDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString(callSuper = true)
+public class LibListExploratoryDTO extends ExploratoryActionDTO<LibListExploratoryDTO> {
+
+    @JsonProperty
+    private String libCacheKey;
+
+    public LibListExploratoryDTO withLibCacheKey(String libCacheKey) {
+        setLibCacheKey(libCacheKey);
+        return this;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/LibraryGroups.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/LibraryGroups.java
new file mode 100644
index 0000000..a5e829d
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/LibraryGroups.java
@@ -0,0 +1,40 @@
+/*
+ * 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.datalab.dto;
+
+public enum LibraryGroups {
+    GROUP_JAVA("java"),
+    GROUP_PIP2("pip2"),
+    GROUP_PIP3("pip3"),
+    GROUP_R_PKG("r_pkg"),
+    GROUP_OS_PKG("os_pkg"),
+    GROUP_OTHERS("others");
+
+    private String name;
+
+    LibraryGroups(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/ResourceBaseDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/ResourceBaseDTO.java
new file mode 100644
index 0000000..bb007b6
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/ResourceBaseDTO.java
@@ -0,0 +1,74 @@
+/*
+ * 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.datalab.dto;
+
+import com.epam.datalab.dto.base.CloudSettings;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@class")
+public abstract class ResourceBaseDTO<T extends ResourceBaseDTO<?>> {
+    @SuppressWarnings("unchecked")
+    private final T self = (T) this;
+    @JsonProperty("edge_user_name")
+    private String edgeUserName;
+    @JsonProperty
+    private CloudSettings cloudSettings;
+
+    public String getEdgeUserName() {
+        return edgeUserName;
+    }
+
+    public void setEdgeUserName(String edgeUserName) {
+        this.edgeUserName = edgeUserName;
+    }
+
+    public T withEdgeUserName(String edgeUserName) {
+        setEdgeUserName(edgeUserName);
+        return self;
+    }
+
+    public CloudSettings getCloudSettings() {
+        return cloudSettings;
+    }
+
+    public void setCloudSettings(CloudSettings cloudSettings) {
+        this.cloudSettings = cloudSettings;
+    }
+
+    public T withCloudSettings(CloudSettings cloudSettings) {
+        setCloudSettings(cloudSettings);
+        return self;
+    }
+
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("edgeUserName", edgeUserName)
+                .add("cloudSettings", cloudSettings);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/ResourceEnvBaseDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/ResourceEnvBaseDTO.java
new file mode 100644
index 0000000..f3d42ec
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/ResourceEnvBaseDTO.java
@@ -0,0 +1,71 @@
+/*
+ * 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.datalab.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+public class ResourceEnvBaseDTO<T extends ResourceEnvBaseDTO<?>> extends ResourceSysBaseDTO<T> {
+    @JsonProperty("exploratory_name")
+    private String exploratoryName;
+    @JsonProperty("application")
+    private String applicationName;
+
+    @SuppressWarnings("unchecked")
+    private final T self = (T) this;
+
+    public String getExploratoryName() {
+        return exploratoryName;
+    }
+
+    public void setExploratoryName(String exploratoryName) {
+        this.exploratoryName = exploratoryName;
+    }
+
+    public T withExploratoryName(String exploratoryName) {
+        setExploratoryName(exploratoryName);
+        return self;
+    }
+
+    public String getApplicationName() {
+        return applicationName;
+    }
+
+    public void setApplicationName(String applicationName) {
+        this.applicationName = applicationName;
+    }
+
+    public T withApplicationName(String applicationName) {
+        setApplicationName(applicationName);
+        return self;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("applicationName", applicationName)
+                .add("exploratoryName", exploratoryName);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/ResourceSysBaseDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/ResourceSysBaseDTO.java
new file mode 100644
index 0000000..2c3cf35
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/ResourceSysBaseDTO.java
@@ -0,0 +1,87 @@
+/*
+ * 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.datalab.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+public class ResourceSysBaseDTO<T extends ResourceSysBaseDTO<?>> extends ResourceBaseDTO<T> {
+    @SuppressWarnings("unchecked")
+    private final T self = (T) this;
+    @JsonProperty("conf_service_base_name")
+    private String serviceBaseName;
+    @JsonProperty("conf_os_family")
+    private String confOsFamily;
+    @JsonProperty("conf_key_dir")
+    private String confKeyDir;
+
+    public String getServiceBaseName() {
+        return serviceBaseName;
+    }
+
+    public void setServiceBaseName(String serviceBaseName) {
+        this.serviceBaseName = serviceBaseName;
+    }
+
+    public T withServiceBaseName(String serviceBaseName) {
+        setServiceBaseName(serviceBaseName);
+        return self;
+    }
+
+    public String getConfOsFamily() {
+        return confOsFamily;
+    }
+
+    public void setConfOsFamily(String confOsFamily) {
+        this.confOsFamily = confOsFamily;
+    }
+
+    public T withConfOsFamily(String confOsFamily) {
+        setConfOsFamily(confOsFamily);
+        return self;
+    }
+
+
+    public String getConfKeyDir() {
+        return confKeyDir;
+    }
+
+    public void setConfKeyDir(String confKeyDir) {
+        this.confKeyDir = confKeyDir;
+    }
+
+    public T withConfKeyDir(String confKeyDir) {
+        setConfKeyDir(confKeyDir);
+        return self;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("serviceBaseName", serviceBaseName)
+                .add("confKeyDir", confKeyDir)
+                .add("confOsFamily", confOsFamily);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/ResourceURL.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/ResourceURL.java
new file mode 100644
index 0000000..8972ff3
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/ResourceURL.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * Describe URL of resource.
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ResourceURL {
+    @JsonProperty("description")
+    private String description;
+    @JsonProperty("url")
+    private String url;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/SchedulerJobDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/SchedulerJobDTO.java
new file mode 100644
index 0000000..f152e17
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/SchedulerJobDTO.java
@@ -0,0 +1,86 @@
+/*
+ * 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.datalab.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneOffset;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Stores info about a scheduler job (general duration, days to repeat, time to start and finish).
+ */
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class SchedulerJobDTO {
+
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
+    @JsonProperty("begin_date")
+    private LocalDate beginDate;
+
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
+    @JsonProperty("finish_date")
+    private LocalDate finishDate;
+
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm")
+    @JsonProperty("start_time")
+    private LocalTime startTime;
+
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm")
+    @JsonProperty("end_time")
+    private LocalTime endTime;
+
+    @JsonProperty("start_days_repeat")
+    private List<DayOfWeek> startDaysRepeat = Collections.emptyList();
+
+    @JsonProperty("stop_days_repeat")
+    private List<DayOfWeek> stopDaysRepeat = Collections.emptyList();
+
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm")
+    @JsonProperty("terminate_datetime")
+    private LocalDateTime terminateDateTime;
+
+    @JsonProperty("timezone_offset")
+    private ZoneOffset timeZoneOffset;
+
+    @JsonProperty("sync_start_required")
+    private boolean syncStartRequired = true;
+
+    @JsonProperty("max_inactivity")
+    private Long maxInactivity;
+    @JsonProperty("check_inactivity_required")
+    private boolean checkInactivityRequired;
+    @JsonProperty("consider_inactivity")
+    private boolean considerInactivity = true;
+
+    public boolean inactivityScheduler() {
+        return Objects.nonNull(maxInactivity);
+    }
+
+}
\ No newline at end of file
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/StatusBaseDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/StatusBaseDTO.java
new file mode 100644
index 0000000..0001c9c
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/StatusBaseDTO.java
@@ -0,0 +1,127 @@
+/*
+ * 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.datalab.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.Date;
+
+public abstract class StatusBaseDTO<T extends StatusBaseDTO<?>> {
+    @JsonProperty("request_id")
+    private String requestId;
+    @JsonProperty
+    private String user;
+    @JsonProperty
+    private String status;
+    @JsonProperty("error_message")
+    private String errorMessage;
+    @JsonProperty("up_time")
+    private Date uptime;
+
+    @SuppressWarnings("unchecked")
+    private final T self = (T) this;
+
+    public String getRequestId() {
+        return requestId;
+    }
+
+    public void setRequestId(String requestId) {
+        this.requestId = requestId;
+    }
+
+    public T withRequestId(String requestId) {
+        setRequestId(requestId);
+        return self;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public T withUser(String user) {
+        setUser(user);
+        return self;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public T withStatus(String status) {
+        setStatus(status);
+        return self;
+    }
+
+    public T withStatus(UserInstanceStatus status) {
+        return withStatus(status.toString());
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+
+    public T withErrorMessage(String errorMessage) {
+        setErrorMessage(errorMessage);
+        return self;
+    }
+
+    public Date getUptime() {
+        return uptime;
+    }
+
+    public void setUptime(Date uptime) {
+        this.uptime = uptime;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T withUptime(Date uptime) {
+        setUptime(uptime);
+        return (T) this;
+    }
+
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("requestId", requestId)
+                .add("user", user)
+                .add("status", status)
+                .add("errorMessage", errorMessage)
+                .add("uptime", uptime);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/StatusEnvBaseDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/StatusEnvBaseDTO.java
new file mode 100644
index 0000000..a72cf0f
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/StatusEnvBaseDTO.java
@@ -0,0 +1,117 @@
+/*
+ * 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.datalab.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+public abstract class StatusEnvBaseDTO<T extends StatusEnvBaseDTO<?>> extends StatusBaseDTO<T> {
+    @SuppressWarnings("unchecked")
+    private final T self = (T) this;
+    @JsonProperty("instance_id")
+    private String instanceId;
+    @JsonProperty("exploratory_name")
+    private String exploratoryName;
+    private String project;
+    @JsonProperty("exploratory_id")
+    private String exploratoryId;
+    @JsonProperty("exploratory_template_name")
+    private String exploratoryTemplateName;
+
+    public String getInstanceId() {
+        return instanceId;
+    }
+
+    private void setInstanceId(String instanceId) {
+        this.instanceId = instanceId;
+    }
+
+    public T withInstanceId(String instanceId) {
+        setInstanceId(instanceId);
+        return self;
+    }
+
+    public String getExploratoryName() {
+        return exploratoryName;
+    }
+
+    public void setExploratoryName(String exploratoryName) {
+        this.exploratoryName = exploratoryName;
+    }
+
+    public T withExploratoryName(String exploratoryName) {
+        setExploratoryName(exploratoryName);
+        return self;
+    }
+
+    public String getProject() {
+        return project;
+    }
+
+    public void setProject(String project) {
+        this.project = project;
+    }
+
+    public T withProject(String project) {
+        setProject(project);
+        return self;
+    }
+
+    public String getExploratoryId() {
+        return exploratoryId;
+    }
+
+    public void setExploratoryId(String exploratoryId) {
+        this.exploratoryId = exploratoryId;
+    }
+
+    public T withExploratoryId(String exploratoryId) {
+        setExploratoryId(exploratoryId);
+        return self;
+    }
+
+    public String getExploratoryTemplateName() {
+        return exploratoryTemplateName;
+    }
+
+    private void setExploratoryTemplateName(String exploratoryTemplateName) {
+        this.exploratoryTemplateName = exploratoryTemplateName;
+    }
+
+    public T withExploratoryTemplateName(String exploratoryTemplateName) {
+        setExploratoryTemplateName(exploratoryTemplateName);
+        return self;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("instanceId", instanceId)
+                .add("exploratoryName", exploratoryName)
+                .add("exploratoryId", exploratoryId)
+                .add("exploratoryTemplateName", exploratoryTemplateName);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/UserEnvironmentResources.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/UserEnvironmentResources.java
new file mode 100644
index 0000000..6fc6319
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/UserEnvironmentResources.java
@@ -0,0 +1,62 @@
+/*
+ * 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.datalab.dto;
+
+import com.epam.datalab.dto.status.EnvResourceList;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+public class UserEnvironmentResources extends ResourceSysBaseDTO<UserEnvironmentResources> {
+    @JsonProperty("edge_list_resources")
+    private EnvResourceList resourceList;
+
+    /**
+     * Return the list of resources (hosts, clusters, storages).
+     */
+    public EnvResourceList getResourceList() {
+        return resourceList;
+    }
+
+    /**
+     * Set the list of resources (hosts, clusters, storages).
+     */
+    public void setResourceList(EnvResourceList resourceList) {
+        this.resourceList = resourceList;
+    }
+
+    /**
+     * Set the list of resources (hosts, clusters, storages).
+     */
+    public UserEnvironmentResources withResourceList(EnvResourceList resourceList) {
+        setResourceList(resourceList);
+        return this;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("resourceList", resourceList);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/UserInstanceDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/UserInstanceDTO.java
new file mode 100644
index 0000000..12f7a20
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/UserInstanceDTO.java
@@ -0,0 +1,192 @@
+/*
+ * 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.datalab.dto;
+
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.dto.exploratory.LibInstallDTO;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Stores info about the user notebook.
+ */
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UserInstanceDTO {
+    @JsonProperty("_id")
+    private String id;
+    @JsonProperty
+    private String user;
+    @JsonProperty("exploratory_name")
+    private String exploratoryName;
+    @JsonProperty("exploratory_id")
+    private String exploratoryId;
+    @JsonProperty("image")
+    private String imageName;
+    @JsonProperty("version")
+    private String imageVersion;
+    @JsonProperty("project")
+    private String project;
+    @JsonProperty("endpoint")
+    private String endpoint;
+    @JsonProperty("cloud_provider")
+    private String cloudProvider;
+    @JsonProperty("template_name")
+    private String templateName;
+    @JsonProperty
+    private String status;
+    @JsonProperty
+    private String shape;
+    @JsonProperty("exploratory_url")
+    private List<ResourceURL> resourceUrl;
+    @JsonProperty("up_time")
+    private Date uptime;
+    @JsonProperty("computational_resources")
+    private List<UserComputationalResource> resources = new ArrayList<>();
+    @JsonProperty("private_ip")
+    private String privateIp;
+    @JsonProperty("scheduler_data")
+    private SchedulerJobDTO schedulerData;
+    @JsonProperty("reupload_key_required")
+    private boolean reuploadKeyRequired = false;
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private List<LibInstallDTO> libs = Collections.emptyList();
+    @JsonProperty("last_activity")
+    private LocalDateTime lastActivity;
+    @JsonProperty("cluster_config")
+    private List<ClusterConfig> clusterConfig;
+    @JsonProperty
+    private Map<String, String> tags;
+
+    /**
+     * Sets the user login name.
+     */
+    public UserInstanceDTO withUser(String user) {
+        setUser(user);
+        return this;
+    }
+
+    /**
+     * Sets the name of exploratory.
+     */
+    public UserInstanceDTO withExploratoryName(String exploratoryName) {
+        setExploratoryName(exploratoryName);
+        return this;
+    }
+
+    /**
+     * Sets the exploratory id.
+     */
+    public UserInstanceDTO withExploratoryId(String exploratoryId) {
+        setExploratoryId(exploratoryId);
+        return this;
+    }
+
+    /**
+     * Sets the image name.
+     */
+    public UserInstanceDTO withImageName(String imageName) {
+        setImageName(imageName);
+        return this;
+    }
+
+    public UserInstanceDTO withClusterConfig(List<ClusterConfig> config) {
+        setClusterConfig(config);
+        return this;
+    }
+
+    /**
+     * Sets the image version.
+     */
+    public UserInstanceDTO withImageVersion(String imageVersion) {
+        setImageVersion(imageVersion);
+        return this;
+    }
+
+    /**
+     * Sets the name of template.
+     */
+    public UserInstanceDTO withTemplateName(String templateName) {
+        setTemplateName(templateName);
+        return this;
+    }
+
+    /**
+     * Sets the status of notebook.
+     */
+    public UserInstanceDTO withStatus(String status) {
+        setStatus(status);
+        return this;
+    }
+
+    /**
+     * Sets the name of notebook shape.
+     */
+    public UserInstanceDTO withShape(String shape) {
+        setShape(shape);
+        return this;
+    }
+
+    public UserInstanceDTO withProject(String project) {
+        setProject(project);
+        return this;
+    }
+
+    /**
+     * Sets a list of user's computational resources for notebook.
+     */
+    public UserInstanceDTO withResources(List<UserComputationalResource> resources) {
+        setResources(resources);
+        return this;
+    }
+
+    /**
+     * Sets library list.
+     */
+    public UserInstanceDTO withLibs(List<LibInstallDTO> libs) {
+        setLibs(libs);
+        return this;
+    }
+
+    public UserInstanceDTO withEndpoint(String endpoint) {
+        setEndpoint(endpoint);
+        return this;
+    }
+
+    public UserInstanceDTO withCloudProvider(String cloudProvider) {
+        setCloudProvider(cloudProvider);
+        return this;
+    }
+
+    public UserInstanceDTO withTags(Map<String, String> tags) {
+        setTags(tags);
+        return this;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/UserInstanceStatus.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/UserInstanceStatus.java
new file mode 100644
index 0000000..4682484
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/UserInstanceStatus.java
@@ -0,0 +1,67 @@
+/*
+ * 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.datalab.dto;
+
+public enum UserInstanceStatus {
+    CREATING("creating"),
+    CREATED("created"),
+    STARTING("starting"),
+    CONFIGURING("configuring"),
+    RUNNING("running"),
+    STOPPING("stopping"),
+    STOPPED("stopped"),
+    TERMINATING("terminating"),
+    TERMINATED("terminated"),
+    FAILED("failed"),
+    CREATING_IMAGE("creating image"),
+    RECONFIGURING("reconfiguring"),
+    REUPLOADING_KEY("reuploading key");
+
+    private String name;
+
+    UserInstanceStatus(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    public static UserInstanceStatus of(String status) {
+        if (status != null) {
+            for (UserInstanceStatus uis : UserInstanceStatus.values()) {
+                if (status.equalsIgnoreCase(uis.toString())) {
+                    return uis;
+                }
+            }
+        }
+        return null;
+    }
+
+    public boolean in(UserInstanceStatus... statusList) {
+        for (UserInstanceStatus status : statusList) {
+            if (this.equals(status)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/AwsCloudSettings.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/AwsCloudSettings.java
new file mode 100644
index 0000000..a3ded0c
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/AwsCloudSettings.java
@@ -0,0 +1,102 @@
+/*
+ * 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.datalab.dto.aws;
+
+import com.epam.datalab.dto.base.CloudSettings;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class AwsCloudSettings extends CloudSettings {
+
+    @JsonProperty("aws_iam_user")
+    private String awsIamUser;
+    @JsonProperty("aws_region")
+    private String awsRegion;
+    @JsonProperty("aws_subnet_id")
+    private String awsSubnetId;
+    @JsonProperty("aws_security_groups_ids")
+    private String awsSecurityGroupIds;
+    @JsonProperty("aws_vpc_id")
+    private String awsVpcId;
+    @JsonProperty("conf_tag_resource_id")
+    private String confTagResourceId;
+    @JsonProperty("aws_notebook_subnet_id")
+    private String awsNotebookSubnetId;
+    @JsonProperty("aws_notebook_vpc_id")
+    private String awsNotebookVpcId;
+    @JsonProperty("aws_zone")
+    private String zone;
+    @JsonProperty("ldap_hostname")
+    protected String ldapHost;
+    @JsonProperty("ldap_dn")
+    protected String ldapDn;
+    @JsonProperty("ldap_ou")
+    protected String ldapOu;
+    @JsonProperty("ldap_service_username")
+    protected String ldapUser;
+    @JsonProperty("ldap_service_password")
+    protected String ldapPassword;
+    @JsonProperty("conf_os_family")
+    protected String os;
+    @JsonProperty("conf_cloud_provider")
+    protected String cloud;
+    @JsonProperty("conf_service_base_name")
+    protected String sbn;
+    @JsonProperty("conf_key_dir")
+    protected String confKeyDir;
+    @JsonProperty("conf_image_enabled")
+    private String imageEnabled;
+    @JsonProperty("conf_stepcerts_enabled")
+    private String stepCertsEnabled;
+    @JsonProperty("conf_stepcerts_root_ca")
+    private String stepCertsRootCA;
+    @JsonProperty("conf_stepcerts_kid")
+    private String stepCertsKid;
+    @JsonProperty("conf_stepcerts_kid_password")
+    private String stepCertsKidPassword;
+    @JsonProperty("conf_stepcerts_ca_url")
+    private String stepCertsCAURL;
+    @JsonProperty("keycloak_auth_server_url")
+    private String keycloakAuthServerUrl;
+    @JsonProperty("keycloak_realm_name")
+    private String keycloakRealmName;
+    @JsonProperty("keycloak_user")
+    private String keycloakUser;
+    @JsonProperty("keycloak_user_password")
+    private String keycloakUserPassword;
+
+    @Override
+    @JsonIgnore
+    public String getIamUser() {
+        return awsIamUser;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/AwsComputationalResource.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/AwsComputationalResource.java
new file mode 100644
index 0000000..8e9f45c
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/AwsComputationalResource.java
@@ -0,0 +1,78 @@
+/*
+ * 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.datalab.dto.aws.computational;
+
+import com.epam.datalab.dto.ResourceURL;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Stores info about the user's computational resources for notebook.
+ */
+@ToString(callSuper = true)
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public class AwsComputationalResource extends UserComputationalResource {
+
+	@JsonProperty("instance_id")
+	private String instanceId;
+	@JsonProperty("master_node_shape")
+	private String masterShape;
+	@JsonProperty("slave_node_shape")
+	private String slaveShape;
+	@JsonProperty("slave_node_spot")
+	private Boolean slaveSpot;
+	@JsonProperty("slave_node_spot_pct_price")
+	private Integer slaveSpotPctPrice;
+	@JsonProperty("total_instance_number")
+	private String slaveNumber;
+	@JsonProperty("emr_version")
+	private String version;
+
+	@Builder
+	public AwsComputationalResource(String computationalName, String computationalId, String imageName,
+									String templateName, String status, Date uptime,
+									SchedulerJobDTO schedulerJobData, boolean reuploadKeyRequired,
+									String instanceId, String masterShape, String slaveShape, Boolean slaveSpot,
+									Integer slaveSpotPctPrice, String slaveNumber, String version,
+									List<ResourceURL> resourceURL, LocalDateTime lastActivity,
+									List<ClusterConfig> config, Map<String, String> tags, int totalInstanceCount) {
+		super(computationalName, computationalId, imageName, templateName, status, uptime, schedulerJobData,
+				reuploadKeyRequired, resourceURL, lastActivity, tags, totalInstanceCount);
+		this.instanceId = instanceId;
+		this.masterShape = masterShape;
+		this.slaveShape = slaveShape;
+		this.slaveSpot = slaveSpot;
+		this.slaveSpotPctPrice = slaveSpotPctPrice;
+		this.slaveNumber = slaveNumber;
+		this.version = version;
+		this.config = config;
+	}
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/AwsComputationalTerminateDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/AwsComputationalTerminateDTO.java
new file mode 100644
index 0000000..cc0160b
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/AwsComputationalTerminateDTO.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.datalab.dto.aws.computational;
+
+import com.epam.datalab.dto.computational.ComputationalTerminateDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+public class AwsComputationalTerminateDTO extends ComputationalTerminateDTO {
+
+    @JsonProperty("emr_cluster_name")
+    private String clusterName;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/ClusterConfig.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/ClusterConfig.java
new file mode 100644
index 0000000..d8a4e72
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/ClusterConfig.java
@@ -0,0 +1,41 @@
+/*
+ * 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.datalab.dto.aws.computational;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+import java.util.Map;
+
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ClusterConfig {
+    @JsonProperty("Classification")
+    @NotEmpty(message = "'Classification' field should not be empty")
+    private String classification;
+    @JsonProperty("Properties")
+    @NotNull(message = "'Properties' field should not be empty")
+    private Map<String, Object> properties;
+    @JsonProperty("Configurations")
+    private List<ClusterConfig> configurations;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/ComputationalConfigAws.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/ComputationalConfigAws.java
new file mode 100644
index 0000000..0a314b2
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/ComputationalConfigAws.java
@@ -0,0 +1,53 @@
+/*
+ * 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.datalab.dto.aws.computational;
+
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+public class ComputationalConfigAws extends ComputationalBase<ComputationalConfigAws> {
+    @JsonProperty("emr_version")
+    private String version;
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public ComputationalConfigAws withVersion(String version) {
+        setVersion(version);
+        return this;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("version", version);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/ComputationalCreateAws.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/ComputationalCreateAws.java
new file mode 100644
index 0000000..bb1eeb9
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/ComputationalCreateAws.java
@@ -0,0 +1,165 @@
+/*
+ * 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.datalab.dto.aws.computational;
+
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.List;
+
+public class ComputationalCreateAws extends ComputationalBase<ComputationalCreateAws> {
+    @JsonProperty("emr_instance_count")
+    private String instanceCount;
+    @JsonProperty("emr_master_instance_type")
+    private String masterInstanceType;
+    @JsonProperty("emr_slave_instance_type")
+    private String slaveInstanceType;
+    @JsonProperty("emr_slave_instance_spot")
+    private Boolean slaveInstanceSpot;
+    @JsonProperty("emr_slave_instance_spot_pct_price")
+    private Integer slaveInstanceSpotPctPrice;
+    @JsonProperty("emr_version")
+    private String version;
+    @JsonProperty("emr_configurations")
+    private List<ClusterConfig> config;
+    @JsonProperty("conf_shared_image_enabled")
+    private String sharedImageEnabled;
+
+    public String getInstanceCount() {
+        return instanceCount;
+    }
+
+    public void setInstanceCount(String instanceCount) {
+        this.instanceCount = instanceCount;
+    }
+
+    public ComputationalCreateAws withInstanceCount(String instanceCount) {
+        setInstanceCount(instanceCount);
+        return this;
+    }
+
+    public String getMasterInstanceType() {
+        return masterInstanceType;
+    }
+
+    public void setMasterInstanceType(String masterInstanceType) {
+        this.masterInstanceType = masterInstanceType;
+    }
+
+    public ComputationalCreateAws withMasterInstanceType(String masterInstanceType) {
+        setMasterInstanceType(masterInstanceType);
+        return this;
+    }
+
+    public String getSlaveInstanceType() {
+        return slaveInstanceType;
+    }
+
+    public void setSlaveInstanceType(String slaveInstanceType) {
+        this.slaveInstanceType = slaveInstanceType;
+    }
+
+    public ComputationalCreateAws withSlaveInstanceType(String slaveInstanceType) {
+        setSlaveInstanceType(slaveInstanceType);
+        return this;
+    }
+
+    public Boolean getSlaveInstanceSpot() {
+        return slaveInstanceSpot;
+    }
+
+    public void setSlaveInstanceSpot(Boolean slaveInstanceSpot) {
+        this.slaveInstanceSpot = slaveInstanceSpot;
+    }
+
+    public ComputationalCreateAws withSlaveInstanceSpot(Boolean slaveInstanceSpot) {
+        setSlaveInstanceSpot(slaveInstanceSpot);
+        return this;
+    }
+
+    public Integer getSlaveInstanceSpotPctPrice() {
+        return slaveInstanceSpotPctPrice;
+    }
+
+    public void setSlaveInstanceSpotPctPrice(Integer slaveInstanceSpotPctPrice) {
+        this.slaveInstanceSpotPctPrice = slaveInstanceSpotPctPrice;
+    }
+
+    public ComputationalCreateAws withSlaveInstanceSpotPctPrice(Integer slaveInstanceSpotPctPrice) {
+        setSlaveInstanceSpotPctPrice(slaveInstanceSpotPctPrice);
+        return this;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public ComputationalCreateAws withVersion(String version) {
+        setVersion(version);
+        return this;
+    }
+
+    public List<ClusterConfig> getConfig() {
+        return config;
+    }
+
+    public void setConfig(List<ClusterConfig> config) {
+        this.config = config;
+    }
+
+    public ComputationalCreateAws withConfig(List<ClusterConfig> config) {
+        setConfig(config);
+        return this;
+    }
+
+    public String getSharedImageEnabled() {
+        return sharedImageEnabled;
+    }
+
+    public void setSharedImageEnabled(String sharedImageEnabled) {
+        this.sharedImageEnabled = sharedImageEnabled;
+    }
+
+    public ComputationalCreateAws withSharedImageEnabled(String sharedImageEnabled) {
+        setSharedImageEnabled(sharedImageEnabled);
+        return this;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("version", version)
+                .add("masterInstanceType", masterInstanceType)
+                .add("slaveInstanceType", slaveInstanceType)
+                .add("slaveInstanceSpot", slaveInstanceSpot)
+                .add("slaveInstanceSpotPctPrice", slaveInstanceSpotPctPrice)
+                .add("instanceCount", instanceCount);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/SparkComputationalConfigAws.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/SparkComputationalConfigAws.java
new file mode 100644
index 0000000..8242b9d
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/SparkComputationalConfigAws.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab.dto.aws.computational;
+
+import com.epam.datalab.dto.azure.computational.SparkComputationalConfigAzure;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+public class SparkComputationalConfigAws extends ComputationalBase<SparkComputationalConfigAzure> {
+
+    @JsonProperty("dataengine_instance_count")
+    private String dataEngineInstanceCount;
+
+    public SparkComputationalConfigAws withDataEngineInstanceCount(String dataEngineInstanceCount) {
+        this.dataEngineInstanceCount = dataEngineInstanceCount;
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("dataEngineInstanceCount", dataEngineInstanceCount);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/SparkComputationalCreateAws.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/SparkComputationalCreateAws.java
new file mode 100644
index 0000000..db2ca7b
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/computational/SparkComputationalCreateAws.java
@@ -0,0 +1,78 @@
+/*
+ * 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.datalab.dto.aws.computational;
+
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+import java.util.List;
+
+public class SparkComputationalCreateAws extends ComputationalBase<SparkComputationalCreateAws> {
+
+    @JsonProperty("dataengine_instance_count")
+    private String dataEngineInstanceCount;
+    @JsonProperty("aws_dataengine_slave_shape")
+    private String dataEngineSlaveShape;
+    @JsonProperty("aws_dataengine_master_shape")
+    private String dataEngineMasterShape;
+    @JsonProperty("spark_configurations")
+    private List<ClusterConfig> config;
+    @JsonProperty("conf_shared_image_enabled")
+    private String sharedImageEnabled;
+
+    public SparkComputationalCreateAws withDataEngineInstanceCount(String dataEngineInstanceCount) {
+        this.dataEngineInstanceCount = dataEngineInstanceCount;
+        return this;
+    }
+
+    public SparkComputationalCreateAws withDataEngineSlaveShape(String dataEngineSlaveSize) {
+        this.dataEngineSlaveShape = dataEngineSlaveSize;
+        return this;
+    }
+
+    public SparkComputationalCreateAws withDataEngineMasterShape(String dataEngineMasterSize) {
+        this.dataEngineMasterShape = dataEngineMasterSize;
+        return this;
+    }
+
+    public SparkComputationalCreateAws withConfig(List<ClusterConfig> config) {
+        this.config = config;
+        return this;
+    }
+
+    public SparkComputationalCreateAws withSharedImageEnabled(String sharedImageEnabled) {
+        this.sharedImageEnabled = sharedImageEnabled;
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("dataEngineInstanceCount", dataEngineInstanceCount)
+                .add("dataEngineSlaveShape", dataEngineSlaveShape)
+                .add("dataEngineMasterShape", dataEngineMasterShape);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/edge/EdgeCreateAws.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/edge/EdgeCreateAws.java
new file mode 100644
index 0000000..2f341ac
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/edge/EdgeCreateAws.java
@@ -0,0 +1,53 @@
+/*
+ * 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.datalab.dto.aws.edge;
+
+import com.epam.datalab.dto.ResourceSysBaseDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+public class EdgeCreateAws extends ResourceSysBaseDTO<EdgeCreateAws> {
+    @JsonProperty("edge_elastic_ip")
+    private String edgeElasticIp;
+
+    public String getEdgeElasticIp() {
+        return edgeElasticIp;
+    }
+
+    public void setEdgeElasticIp(String edgeElasticIp) {
+        this.edgeElasticIp = edgeElasticIp;
+    }
+
+    public EdgeCreateAws withEdgeElasticIp(String edgeElasticIp) {
+        setEdgeElasticIp(edgeElasticIp);
+        return this;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("edgeElasticIp", edgeElasticIp);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/edge/EdgeInfoAws.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/edge/EdgeInfoAws.java
new file mode 100644
index 0000000..813ad11
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/edge/EdgeInfoAws.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.dto.aws.edge;
+
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class EdgeInfoAws extends EdgeInfo {
+    @JsonProperty("user_own_bicket_name")
+    private String userOwnBucketName;
+    @JsonProperty("notebook_profile")
+    private String notebookProfile;
+    @JsonProperty("shared_bucket_name")
+    private String sharedBucketName;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/exploratory/ExploratoryCreateAws.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/exploratory/ExploratoryCreateAws.java
new file mode 100644
index 0000000..c3fe399
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/exploratory/ExploratoryCreateAws.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab.dto.aws.exploratory;
+
+import com.epam.datalab.dto.exploratory.ExploratoryCreateDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+public class ExploratoryCreateAws extends ExploratoryCreateDTO<ExploratoryCreateAws> {
+    @JsonProperty("aws_notebook_instance_type")
+    private String notebookInstanceType;
+
+    public String getNotebookInstanceType() {
+        return notebookInstanceType;
+    }
+
+    public void setNotebookInstanceType(String notebookInstanceType) {
+        this.notebookInstanceType = notebookInstanceType;
+    }
+
+    public ExploratoryCreateAws withNotebookInstanceType(String notebookInstanceType) {
+        setNotebookInstanceType(notebookInstanceType);
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("notebookInstanceType", notebookInstanceType);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/keyload/UploadFileAws.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/keyload/UploadFileAws.java
new file mode 100644
index 0000000..393a59d
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/aws/keyload/UploadFileAws.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.dto.aws.keyload;
+
+import com.epam.datalab.dto.aws.edge.EdgeCreateAws;
+import com.epam.datalab.dto.base.keyload.UploadFile;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class UploadFileAws extends UploadFile {
+    @JsonProperty
+    private EdgeCreateAws edge;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/AzureCloudSettings.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/AzureCloudSettings.java
new file mode 100644
index 0000000..9a1fbe3
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/AzureCloudSettings.java
@@ -0,0 +1,96 @@
+/*
+ * 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.datalab.dto.azure;
+
+import com.epam.datalab.dto.base.CloudSettings;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class AzureCloudSettings extends CloudSettings {
+
+    @JsonProperty("azure_region")
+    private String azureRegion;
+    @JsonProperty("azure_iam_user")
+    private String azureIamUser;
+    @JsonProperty("conf_service_base_name")
+    protected String sbn;
+    @JsonProperty("conf_os_family")
+    protected String os;
+    @JsonProperty("conf_cloud_provider")
+    protected String cloud;
+    @JsonProperty("azure_vpc_name")
+    private String azureVpcName;
+    @JsonProperty("azure_subnet_name")
+    private String azureSubnetName;
+    @JsonProperty("azure_resource_group_name")
+    private String azureResourceGroupName;
+    @JsonProperty("azure_security_group_name")
+    private String azureSecurityGroupName;
+    @JsonProperty("ldap_hostname")
+    protected String ldapHost;
+    @JsonProperty("ldap_dn")
+    protected String ldapDn;
+    @JsonProperty("ldap_ou")
+    protected String ldapOu;
+    @JsonProperty("ldap_service_username")
+    protected String ldapUser;
+    @JsonProperty("ldap_service_password")
+    protected String ldapPassword;
+    @JsonProperty("conf_key_dir")
+    protected String confKeyDir;
+    @JsonProperty("conf_image_enabled")
+    private String imageEnabled;
+    @JsonProperty("conf_stepcerts_enabled")
+    private String stepCertsEnabled;
+    @JsonProperty("conf_stepcerts_root_ca")
+    private String stepCertsRootCA;
+    @JsonProperty("conf_stepcerts_kid")
+    private String stepCertsKid;
+    @JsonProperty("conf_stepcerts_kid_password")
+    private String stepCertsKidPassword;
+    @JsonProperty("conf_stepcerts_ca_url")
+    private String stepCertsCAURL;
+    @JsonProperty("keycloak_auth_server_url")
+    private String keycloakAuthServerUrl;
+    @JsonProperty("keycloak_realm_name")
+    private String keycloakRealmName;
+    @JsonProperty("keycloak_user")
+    private String keycloakUser;
+    @JsonProperty("keycloak_user_password")
+    private String keycloakUserPassword;
+
+    @Override
+    @JsonIgnore
+    public String getIamUser() {
+        return azureIamUser;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/auth/AuthorizationCodeFlowResponse.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/auth/AuthorizationCodeFlowResponse.java
new file mode 100644
index 0000000..467affd
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/auth/AuthorizationCodeFlowResponse.java
@@ -0,0 +1,63 @@
+/*
+ * 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.datalab.dto.azure.auth;
+
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.ToString;
+
+import javax.ws.rs.FormParam;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+@ToString(exclude = "code")
+public class AuthorizationCodeFlowResponse {
+
+    @JsonProperty
+    @FormParam("state")
+    private String state;
+    @JsonProperty
+    @FormParam("code")
+    private String code;
+    @JsonProperty
+    @FormParam("error")
+    private String error;
+    @JsonProperty("error_description")
+    @FormParam("error_description")
+    private String errorDescription;
+
+    @JsonIgnore
+    public boolean isSuccessful() {
+        return state != null && !state.isEmpty() && code != null && !code.isEmpty();
+    }
+
+    @JsonIgnore
+    public boolean isFailed() {
+        return error != null && !error.isEmpty();
+    }
+
+    @JsonIgnore
+    public boolean isValid() {
+        return isSuccessful() || isFailed();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/SparkComputationalConfigAzure.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/SparkComputationalConfigAzure.java
new file mode 100644
index 0000000..c7d1f16
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/SparkComputationalConfigAzure.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.dto.azure.computational;
+
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+public class SparkComputationalConfigAzure extends ComputationalBase<SparkComputationalConfigAzure> {
+
+    @JsonProperty("dataengine_instance_count")
+    private String dataEngineInstanceCount;
+
+    public SparkComputationalConfigAzure withDataEngineInstanceCount(String dataEngineInstanceCount) {
+        this.dataEngineInstanceCount = dataEngineInstanceCount;
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("dataEngineInstanceCount", dataEngineInstanceCount);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/SparkComputationalCreateAzure.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/SparkComputationalCreateAzure.java
new file mode 100644
index 0000000..fed622a
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/SparkComputationalCreateAzure.java
@@ -0,0 +1,94 @@
+/*
+ * 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.datalab.dto.azure.computational;
+
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+import java.util.List;
+
+public class SparkComputationalCreateAzure extends ComputationalBase<SparkComputationalCreateAzure> {
+    @JsonProperty("dataengine_instance_count")
+    private String dataEngineInstanceCount;
+    @JsonProperty("azure_dataengine_slave_size")
+    private String dataEngineSlaveSize;
+    @JsonProperty("azure_dataengine_master_size")
+    private String dataEngineMasterSize;
+    @JsonProperty("azure_datalake_enable")
+    private String azureDataLakeEnabled;
+    @JsonProperty("azure_user_refresh_token")
+    private String azureUserRefreshToken;
+    @JsonProperty("spark_configurations")
+    private List<ClusterConfig> config;
+    @JsonProperty("conf_shared_image_enabled")
+    private String sharedImageEnabled;
+
+    public SparkComputationalCreateAzure withDataEngineInstanceCount(String dataEngineInstanceCount) {
+        this.dataEngineInstanceCount = dataEngineInstanceCount;
+        return this;
+    }
+
+    public SparkComputationalCreateAzure withDataEngineSlaveSize(String dataEngineSlaveSize) {
+        this.dataEngineSlaveSize = dataEngineSlaveSize;
+        return this;
+    }
+
+    public SparkComputationalCreateAzure withDataEngineMasterSize(String dataEngineMasterSize) {
+        this.dataEngineMasterSize = dataEngineMasterSize;
+        return this;
+    }
+
+    public SparkComputationalCreateAzure withAzureDataLakeEnabled(String azureDataLakeEnabled) {
+        this.azureDataLakeEnabled = azureDataLakeEnabled;
+        return this;
+    }
+
+    public SparkComputationalCreateAzure withAzureUserRefreshToken(String azureUserRefreshToken) {
+        this.azureUserRefreshToken = azureUserRefreshToken;
+        return this;
+    }
+
+    public SparkComputationalCreateAzure withConfig(List<ClusterConfig> config) {
+        this.config = config;
+        return this;
+    }
+
+    public SparkComputationalCreateAzure withSharedImageEnabled(String sharedImageEnabled) {
+        this.sharedImageEnabled = sharedImageEnabled;
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("dataEngineInstanceCount", dataEngineInstanceCount)
+                .add("dataEngineSlaveSize", dataEngineSlaveSize)
+                .add("dataEngineMasterSize", dataEngineMasterSize)
+                .add("azureDataLakeEnabled", azureDataLakeEnabled)
+                .add("azureUserRefreshToken", azureUserRefreshToken != null ? "***" : null);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/edge/EdgeCreateAzure.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/edge/EdgeCreateAzure.java
new file mode 100644
index 0000000..3e4a19d
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/edge/EdgeCreateAzure.java
@@ -0,0 +1,54 @@
+/*
+ * 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.datalab.dto.azure.edge;
+
+import com.epam.datalab.dto.ResourceSysBaseDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+public class EdgeCreateAzure extends ResourceSysBaseDTO<EdgeCreateAzure> {
+    @JsonProperty("azure_datalake_enable")
+    private String azureDataLakeEnable;
+
+    public EdgeCreateAzure withAzureDataLakeEnable(String azureDataLakeEnable) {
+        this.azureDataLakeEnable = azureDataLakeEnable;
+        return this;
+    }
+
+    public String getAzureDataLakeEnable() {
+        return azureDataLakeEnable;
+    }
+
+
+    public void setAzureDataLakeEnable(String azureDataLakeEnable) {
+        this.azureDataLakeEnable = azureDataLakeEnable;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(this)
+                .add("azureDataLakeEnable", azureDataLakeEnable);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/edge/EdgeInfoAzure.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/edge/EdgeInfoAzure.java
new file mode 100644
index 0000000..c5bba7e
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/edge/EdgeInfoAzure.java
@@ -0,0 +1,52 @@
+/*
+ * 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.datalab.dto.azure.edge;
+
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class EdgeInfoAzure extends EdgeInfo {
+    @JsonProperty("user_storage_account_name")
+    private String userStorageAccountName;
+    @JsonProperty("user_container_name")
+    private String userContainerName;
+    @JsonProperty("shared_storage_account_name")
+    private String sharedStorageAccountName;
+    @JsonProperty("shared_container_name")
+    private String sharedContainerName;
+    @JsonProperty("user_storage_account_tag_name")
+    private String userStorageAccountTagName;
+    @JsonProperty("datalake_name")
+    private String dataLakeName;
+    @JsonProperty("datalake_user_directory_name")
+    private String dataLakeDirectoryName;
+    @JsonProperty("datalake_shared_directory_name")
+    private String dataLakeSharedDirectoryName;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/exploratory/ExploratoryActionStartAzure.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/exploratory/ExploratoryActionStartAzure.java
new file mode 100644
index 0000000..b4b9454
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/exploratory/ExploratoryActionStartAzure.java
@@ -0,0 +1,64 @@
+/*
+ * 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.datalab.dto.azure.exploratory;
+
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+public class ExploratoryActionStartAzure extends ExploratoryGitCredsUpdateDTO {
+    @JsonProperty("azure_datalake_enable")
+    private String azureDataLakeEnabled;
+    @JsonProperty("azure_user_refresh_token")
+    private String azureUserRefreshToken;
+
+    public String getAzureDataLakeEnabled() {
+        return azureDataLakeEnabled;
+    }
+
+    public void setAzureDataLakeEnabled(String azureDataLakeEnabled) {
+        this.azureDataLakeEnabled = azureDataLakeEnabled;
+    }
+
+    public String getAzureUserRefreshToken() {
+        return azureUserRefreshToken;
+    }
+
+    public void setAzureUserRefreshToken(String azureUserRefreshToken) {
+        this.azureUserRefreshToken = azureUserRefreshToken;
+    }
+
+    public ExploratoryActionStartAzure withAzureDataLakeEnabled(String azureDataLakeEnabled) {
+        setAzureDataLakeEnabled(azureDataLakeEnabled);
+        return this;
+    }
+
+    public ExploratoryActionStartAzure withAzureUserRefreshToken(String azureUserRefreshToken) {
+        setAzureUserRefreshToken(azureUserRefreshToken);
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("azureDataLakeEnabled", azureDataLakeEnabled)
+                .add("azureUserRefreshToken", azureUserRefreshToken != null ? "***" : null);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/exploratory/ExploratoryActionStopAzure.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/exploratory/ExploratoryActionStopAzure.java
new file mode 100644
index 0000000..adcbd46
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/exploratory/ExploratoryActionStopAzure.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.dto.azure.exploratory;
+
+import com.epam.datalab.dto.exploratory.ExploratoryActionDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+public class ExploratoryActionStopAzure extends ExploratoryActionDTO<ExploratoryActionStopAzure> {
+    @JsonProperty("computational_name")
+    private String computationalName;
+
+    public String getComputationalName() {
+        return computationalName;
+    }
+
+    public ExploratoryActionStopAzure setComputationalName(String computationalName) {
+        this.computationalName = computationalName;
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("computationalName", computationalName);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/exploratory/ExploratoryCreateAzure.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/exploratory/ExploratoryCreateAzure.java
new file mode 100644
index 0000000..8a08dc0
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/exploratory/ExploratoryCreateAzure.java
@@ -0,0 +1,85 @@
+/*
+ * 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.datalab.dto.azure.exploratory;
+
+import com.epam.datalab.dto.exploratory.ExploratoryCreateDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+public class ExploratoryCreateAzure extends ExploratoryCreateDTO<ExploratoryCreateAzure> {
+    @JsonProperty("azure_notebook_instance_size")
+    private String notebookInstanceType;
+    @JsonProperty("azure_datalake_enable")
+    private String azureDataLakeEnabled;
+    @JsonProperty("azure_user_refresh_token")
+    private String azureUserRefreshToken;
+
+    public String getNotebookInstanceType() {
+        return notebookInstanceType;
+    }
+
+    public void setNotebookInstanceType(String notebookInstanceType) {
+        this.notebookInstanceType = notebookInstanceType;
+    }
+
+    public String getAzureDataLakeEnabled() {
+        return azureDataLakeEnabled;
+    }
+
+    public void setAzureDataLakeEnabled(String azureDataLakeEnabled) {
+        this.azureDataLakeEnabled = azureDataLakeEnabled;
+    }
+
+    public String getAzureUserRefreshToken() {
+        return azureUserRefreshToken;
+    }
+
+    public void setAzureUserRefreshToken(String azureUserRefreshToken) {
+        this.azureUserRefreshToken = azureUserRefreshToken;
+    }
+
+    public ExploratoryCreateAzure withNotebookInstanceSize(String notebookInstanceType) {
+        setNotebookInstanceType(notebookInstanceType);
+        return this;
+    }
+
+    public ExploratoryCreateAzure withAzureDataLakeEnabled(String azureDataLakeEnabled) {
+        setAzureDataLakeEnabled(azureDataLakeEnabled);
+        return this;
+    }
+
+    public ExploratoryCreateAzure withAzureUserRefreshToken(String azureUserRefreshToken) {
+        setAzureUserRefreshToken(azureUserRefreshToken);
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("notebookInstanceType", notebookInstanceType)
+                .add("azureDataLakeEnabled", azureDataLakeEnabled)
+                .add("azureUserRefreshToken", azureUserRefreshToken != null ? "***" : null);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/keyload/UploadFileAzure.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/keyload/UploadFileAzure.java
new file mode 100644
index 0000000..4148584
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/keyload/UploadFileAzure.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.dto.azure.keyload;
+
+import com.epam.datalab.dto.azure.edge.EdgeCreateAzure;
+import com.epam.datalab.dto.base.keyload.UploadFile;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class UploadFileAzure extends UploadFile {
+    @JsonProperty
+    private EdgeCreateAzure edge;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/backup/EnvBackupDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/backup/EnvBackupDTO.java
new file mode 100644
index 0000000..a662d2f
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/backup/EnvBackupDTO.java
@@ -0,0 +1,40 @@
+/*
+ * 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.datalab.dto.backup;
+
+import lombok.Builder;
+import lombok.Data;
+import lombok.ToString;
+
+import java.util.List;
+
+@Data
+@Builder
+@ToString
+public class EnvBackupDTO {
+    private final List<String> configFiles;
+    private final List<String> keys;
+    private final List<String> certificates;
+    private final List<String> jars;
+    private final boolean databaseBackup;
+    private final boolean logsBackup;
+    private String backupFile;
+    private String id;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/backup/EnvBackupStatus.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/backup/EnvBackupStatus.java
new file mode 100644
index 0000000..91637ef
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/backup/EnvBackupStatus.java
@@ -0,0 +1,49 @@
+/*
+ * 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.datalab.dto.backup;
+
+import java.util.Arrays;
+
+public enum EnvBackupStatus {
+    CREATING("N/A"), CREATED("N/A"), FAILED("N/A");
+
+    private String message;
+
+    EnvBackupStatus(String message) {
+        this.message = message;
+    }
+
+    public EnvBackupStatus withErrorMessage(String message) {
+        this.message = message;
+        return this;
+    }
+
+    public String message() {
+        return message;
+    }
+
+    public static EnvBackupStatus fromValue(String value) {
+        return Arrays.stream(values())
+                .filter(v -> v.name().equalsIgnoreCase(value))
+                .findAny()
+                .orElseThrow(() ->
+                        new IllegalArgumentException("Wrong value for EnvBackupStatus: " + value));
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/backup/EnvBackupStatusDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/backup/EnvBackupStatusDTO.java
new file mode 100644
index 0000000..76811f3
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/backup/EnvBackupStatusDTO.java
@@ -0,0 +1,56 @@
+/*
+ * 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.datalab.dto.backup;
+
+import com.epam.datalab.dto.StatusBaseDTO;
+import com.google.common.base.MoreObjects;
+import lombok.Getter;
+
+@Getter
+public class EnvBackupStatusDTO extends StatusBaseDTO<EnvBackupStatusDTO> {
+
+    private EnvBackupDTO envBackupDTO;
+    private EnvBackupStatus envBackupStatus;
+
+
+    public EnvBackupStatusDTO withEnvBackupDTO(EnvBackupDTO envBackupDTO) {
+        this.envBackupDTO = envBackupDTO;
+        return this;
+    }
+
+    public EnvBackupStatusDTO withStatus(EnvBackupStatus status) {
+        this.envBackupStatus = status;
+        return withStatus(status.name());
+    }
+
+    public EnvBackupStatusDTO withBackupFile(String backupFile) {
+        if (envBackupDTO != null) {
+            envBackupDTO.setBackupFile(backupFile);
+        }
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("envBackupStatus", envBackupStatus)
+                .add("envBackupDTO", envBackupDTO);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/base/CloudSettings.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/CloudSettings.java
new file mode 100644
index 0000000..5c1ccb8
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/CloudSettings.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.datalab.dto.base;
+
+import com.epam.datalab.util.CloudSettingsDeserializer;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import lombok.Data;
+
+@Data
+@JsonDeserialize(using = CloudSettingsDeserializer.class)
+public abstract class CloudSettings {
+    @JsonIgnore
+    public abstract String getIamUser();
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/base/DataEngineType.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/DataEngineType.java
new file mode 100644
index 0000000..adeb5dc
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/DataEngineType.java
@@ -0,0 +1,66 @@
+/*
+ * 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.datalab.dto.base;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum DataEngineType {
+    CLOUD_SERVICE("dataengine-service"), SPARK_STANDALONE("dataengine");
+
+    private static final String DOCKER_IMAGE_PREFIX = "docker.datalab-";
+
+    private static final Map<String, DataEngineType> INTERNAL_MAP = new HashMap<>();
+
+    static {
+        for (DataEngineType dataEngineType : DataEngineType.values()) {
+            INTERNAL_MAP.put(dataEngineType.getName(), dataEngineType);
+        }
+    }
+
+    private String name;
+
+    DataEngineType(String name) {
+        this.name = name;
+    }
+
+    public String getImage() {
+        return DOCKER_IMAGE_PREFIX + this.name;
+    }
+
+    public static DataEngineType fromString(String name) {
+        return INTERNAL_MAP.get(name);
+    }
+
+    public static DataEngineType fromDockerImageName(String name) {
+        return INTERNAL_MAP.get(name.replace(DOCKER_IMAGE_PREFIX, ""));
+    }
+
+    public static String getDockerImageName(DataEngineType dataEngineType) {
+        return DOCKER_IMAGE_PREFIX + dataEngineType.getName();
+    }
+
+    @JsonValue
+    public String getName() {
+        return name;
+    }
+}
\ No newline at end of file
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/base/computational/ComputationalBase.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/computational/ComputationalBase.java
new file mode 100644
index 0000000..cc0d6ad
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/computational/ComputationalBase.java
@@ -0,0 +1,119 @@
+/*
+ * 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.datalab.dto.base.computational;
+
+import com.epam.datalab.dto.ResourceEnvBaseDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.Map;
+
+public abstract class ComputationalBase<T extends ComputationalBase<?>> extends ResourceEnvBaseDTO<T> {
+    @SuppressWarnings("unchecked")
+    private final T self = (T) this;
+
+    @JsonProperty("computational_name")
+    private String computationalName;
+
+    @JsonProperty("notebook_instance_name")
+    private String notebookInstanceName;
+
+    @JsonProperty("notebook_template_name")
+    private String notebookTemplateName;
+
+    @JsonProperty("project_name")
+    private String project;
+    @JsonProperty("endpoint_name")
+    private String ednpoint;
+
+    @JsonProperty("tags")
+    private Map<String, String> tags;
+
+    public String getComputationalName() {
+        return computationalName;
+    }
+
+    public void setComputationalName(String computationalName) {
+        this.computationalName = computationalName;
+    }
+
+    public T withComputationalName(String computationalName) {
+        setComputationalName(computationalName);
+        return self;
+    }
+
+    public String getNotebookInstanceName() {
+        return notebookInstanceName;
+    }
+
+    public void setNotebookInstanceName(String notebookInstanceName) {
+        this.notebookInstanceName = notebookInstanceName;
+    }
+
+    public T withNotebookInstanceName(String notebookInstanceName) {
+        setNotebookInstanceName(notebookInstanceName);
+        return self;
+    }
+
+    public String getNotebookTemplateName() {
+        return notebookTemplateName;
+    }
+
+    public void setNotebookTemplateName(String notebookTemplateName) {
+        this.notebookTemplateName = notebookTemplateName;
+    }
+
+    public T withNotebookTemplateName(String notebookTemplateName) {
+        setNotebookTemplateName(notebookTemplateName);
+        return self;
+    }
+
+    public T withProject(String project) {
+        this.project = project;
+        return self;
+    }
+
+    public T withTags(Map<String, String> tags) {
+        this.tags = tags;
+        return self;
+    }
+
+    public T withEndpoint(String endpoint) {
+        this.ednpoint = endpoint;
+        return self;
+    }
+
+    public String getProject() {
+        return project;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("computationalName", computationalName)
+                .add("notebookInstanceName", notebookInstanceName)
+                .add("notebookTemplateName", notebookTemplateName);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/base/computational/FullComputationalTemplate.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/computational/FullComputationalTemplate.java
new file mode 100644
index 0000000..09cc0b8
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/computational/FullComputationalTemplate.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.datalab.dto.base.computational;
+
+import com.epam.datalab.dto.imagemetadata.ComputationalMetadataDTO;
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+
+public class FullComputationalTemplate {
+    @JsonUnwrapped
+    private ComputationalMetadataDTO computationalMetadataDTO;
+
+
+    public FullComputationalTemplate(ComputationalMetadataDTO metadataDTO) {
+        this.computationalMetadataDTO = metadataDTO;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/base/edge/EdgeInfo.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/edge/EdgeInfo.java
new file mode 100644
index 0000000..f112383
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/edge/EdgeInfo.java
@@ -0,0 +1,71 @@
+/*
+ * 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.datalab.dto.base.edge;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import lombok.Data;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
+public class EdgeInfo {
+    @JsonProperty("_id")
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private String id;
+
+    @JsonProperty("instance_id")
+    private String instanceId;
+
+    @JsonProperty
+    private String hostname;
+
+    @JsonProperty("public_ip")
+    private String publicIp;
+
+    @JsonProperty
+    private String ip;
+
+    @JsonProperty("key_name")
+    private String keyName;
+
+    @JsonProperty("tunnel_port")
+    private String tunnelPort;
+
+    @JsonProperty("socks_port")
+    private String socksPort;
+
+    @JsonProperty("notebook_sg")
+    private String notebookSg;
+
+    @JsonProperty("edge_sg")
+    private String edgeSg;
+
+    @JsonProperty("notebook_subnet")
+    private String notebookSubnet;
+
+    @JsonProperty("edge_status")
+    private String edgeStatus;
+
+    @JsonProperty("reupload_key_required")
+    private boolean reuploadKeyRequired = false;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/base/keyload/ReuploadFile.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/keyload/ReuploadFile.java
new file mode 100644
index 0000000..dcda54a
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/keyload/ReuploadFile.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.datalab.dto.base.keyload;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class ReuploadFile extends UploadFile {
+    @JsonProperty
+    private String edgeUserName;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/base/keyload/UploadFile.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/keyload/UploadFile.java
new file mode 100644
index 0000000..7ca9810
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/keyload/UploadFile.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.datalab.dto.base.keyload;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class UploadFile {
+    @JsonProperty
+    private String content;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/base/keyload/UploadFileResult.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/keyload/UploadFileResult.java
new file mode 100644
index 0000000..d8e99de
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/keyload/UploadFileResult.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.dto.base.keyload;
+
+import com.epam.datalab.dto.StatusBaseDTO;
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import com.google.common.base.MoreObjects;
+
+public class UploadFileResult<T extends EdgeInfo> extends StatusBaseDTO<UploadFileResult<T>> {
+
+    private T edgeInfo;
+
+    public T getEdgeInfo() {
+        return edgeInfo;
+    }
+
+    public UploadFileResult<T> withEdgeInfo(T edgeInfo) {
+        this.edgeInfo = edgeInfo;
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("edgeInfo", edgeInfo);
+    }
+
+
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/base/project/ProjectResult.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/project/ProjectResult.java
new file mode 100644
index 0000000..ad05d4d
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/base/project/ProjectResult.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab.dto.base.project;
+
+import com.epam.datalab.dto.StatusBaseDTO;
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ProjectResult extends StatusBaseDTO<ProjectResult> {
+    private EdgeInfo edgeInfo;
+    @JsonProperty("project_name")
+    private String projectName;
+    @JsonProperty("endpoint_name")
+    private String endpointName;
+
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/billing/BillingData.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/billing/BillingData.java
new file mode 100644
index 0000000..228fa8d
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/billing/BillingData.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.dto.billing;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+
+import java.time.LocalDate;
+
+@Data
+@Builder
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BillingData {
+    private final String tag;
+    private String application;
+    @JsonProperty("from")
+    private LocalDate usageDateFrom;
+    @JsonProperty("to")
+    private LocalDate usageDateTo;
+    private String product;
+    private String usageType;
+    private Double cost;
+    private String currency;
+    private final String usageDate;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/billing/BillingResourceType.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/billing/BillingResourceType.java
new file mode 100644
index 0000000..6b32025
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/billing/BillingResourceType.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.datalab.dto.billing;
+
+public enum BillingResourceType {
+    EDGE,
+    SSN,
+    ENDPOINT,
+    BUCKET,
+    VOLUME,
+    EXPLORATORY,
+    COMPUTATIONAL,
+    IMAGE
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/bucket/BucketDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/bucket/BucketDTO.java
new file mode 100644
index 0000000..0d67324
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/bucket/BucketDTO.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab.dto.bucket;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BucketDTO {
+    private final String bucket;
+    private final String object;
+    private final String size;
+    private final String lastModifiedDate;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/bucket/BucketDeleteDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/bucket/BucketDeleteDTO.java
new file mode 100644
index 0000000..66ef80f
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/bucket/BucketDeleteDTO.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.datalab.dto.bucket;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BucketDeleteDTO {
+    private final String bucket;
+    private final List<String> objects;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/bucket/FolderUploadDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/bucket/FolderUploadDTO.java
new file mode 100644
index 0000000..37f2559
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/bucket/FolderUploadDTO.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.datalab.dto.bucket;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class FolderUploadDTO {
+    @NotBlank(message = "field cannot be empty")
+    private final String bucket;
+    @NotBlank(message = "field cannot be empty")
+    private final String folder;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/CheckInactivityCallbackDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/CheckInactivityCallbackDTO.java
new file mode 100644
index 0000000..764aab4
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/CheckInactivityCallbackDTO.java
@@ -0,0 +1,57 @@
+/*
+ * 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.datalab.dto.computational;
+
+import com.epam.datalab.dto.ResourceBaseDTO;
+import com.epam.datalab.dto.status.EnvResource;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Setter
+@Getter
+public class CheckInactivityCallbackDTO extends ResourceBaseDTO<CheckInactivityCallbackDTO> {
+
+    @JsonProperty
+    private List<EnvResource> resources;
+
+    @JsonProperty
+    private String id;
+
+    public CheckInactivityCallbackDTO withClusters(List<EnvResource> clusters) {
+        setResources(clusters);
+        return this;
+    }
+
+    public CheckInactivityCallbackDTO withId(String id) {
+        this.id = id;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("resources", resources)
+                .add("id", id)
+                .toString();
+    }
+
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/CheckInactivityStatus.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/CheckInactivityStatus.java
new file mode 100644
index 0000000..35d791d
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/CheckInactivityStatus.java
@@ -0,0 +1,49 @@
+/*
+ * 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.datalab.dto.computational;
+
+import java.util.Arrays;
+
+public enum CheckInactivityStatus {
+
+    COMPLETED("N/A"), FAILED("N/A");
+
+    private String message;
+
+    CheckInactivityStatus(String message) {
+        this.message = message;
+    }
+
+    public CheckInactivityStatus withErrorMessage(String message) {
+        this.message = message;
+        return this;
+    }
+
+    public String message() {
+        return message;
+    }
+
+    public static CheckInactivityStatus fromValue(String value) {
+        return Arrays.stream(values())
+                .filter(v -> v.name().equalsIgnoreCase(value))
+                .findAny()
+                .orElseThrow(() ->
+                        new IllegalArgumentException("Wrong value for CheckInactivityStatus: " + value));
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/CheckInactivityStatusDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/CheckInactivityStatusDTO.java
new file mode 100644
index 0000000..631be43
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/CheckInactivityStatusDTO.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.datalab.dto.computational;
+
+import com.epam.datalab.dto.StatusBaseDTO;
+import lombok.Data;
+
+@Data
+public class CheckInactivityStatusDTO extends StatusBaseDTO<CheckInactivityStatusDTO> {
+
+    private String exploratoryName;
+    private String computationalName;
+    private long lastActivityUnixTime;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalCheckInactivityDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalCheckInactivityDTO.java
new file mode 100644
index 0000000..77256f6
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalCheckInactivityDTO.java
@@ -0,0 +1,57 @@
+/*
+ * 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.datalab.dto.computational;
+
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ComputationalCheckInactivityDTO extends ComputationalBase<ComputationalCheckInactivityDTO> {
+    private String notebookImage;
+    @JsonProperty("computational_id")
+    private String computationalId;
+    private String image;
+
+    public ComputationalCheckInactivityDTO withNotebookImageName(String imageName) {
+        this.notebookImage = imageName;
+        return this;
+    }
+
+    public ComputationalCheckInactivityDTO withComputationalId(String computationalId) {
+        this.computationalId = computationalId;
+        return this;
+    }
+
+    public ComputationalCheckInactivityDTO withImage(String image) {
+        this.image = image;
+        return this;
+    }
+
+    public String getNotebookImage() {
+        return notebookImage;
+    }
+
+    public String getComputationalId() {
+        return computationalId;
+    }
+
+    public String getImage() {
+        return image;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalClusterConfigDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalClusterConfigDTO.java
new file mode 100644
index 0000000..2bc4e1b
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalClusterConfigDTO.java
@@ -0,0 +1,40 @@
+/*
+ * 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.datalab.dto.computational;
+
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ComputationalClusterConfigDTO extends ComputationalBase<ComputationalClusterConfigDTO> {
+
+    @JsonProperty("computational_id")
+    private String copmutationalId;
+    @JsonProperty("spark_configurations")
+    private List<ClusterConfig> config;
+    @JsonProperty("azure_user_refresh_token")
+    private String azureUserRefreshToken;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalStartDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalStartDTO.java
new file mode 100644
index 0000000..52d0785
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalStartDTO.java
@@ -0,0 +1,25 @@
+/*
+ * 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.datalab.dto.computational;
+
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+
+public class ComputationalStartDTO extends ComputationalBase<ComputationalStartDTO> {
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalStatusDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalStatusDTO.java
new file mode 100644
index 0000000..a09cb50
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalStatusDTO.java
@@ -0,0 +1,118 @@
+/*
+ * 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.datalab.dto.computational;
+
+import com.epam.datalab.dto.ResourceURL;
+import com.epam.datalab.dto.StatusEnvBaseDTO;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.Date;
+import java.util.List;
+
+public class ComputationalStatusDTO extends StatusEnvBaseDTO<ComputationalStatusDTO> {
+    @JsonProperty("computational_url")
+    private List<ResourceURL> resourceUrl;
+    @JsonProperty("computational_id")
+    private String computationalId;
+    @JsonProperty("computational_name")
+    private String computationalName;
+    @JsonProperty("last_activity")
+    private Date lastActivity;
+    @JsonProperty
+    private List<ClusterConfig> config;
+
+    public String getComputationalId() {
+        return computationalId;
+    }
+
+    public void setComputationalId(String computationalId) {
+        this.computationalId = computationalId;
+    }
+
+    public ComputationalStatusDTO withComputationalId(String computationalId) {
+        setComputationalId(computationalId);
+        return this;
+    }
+
+    public List<ResourceURL> getResourceUrl() {
+        return resourceUrl;
+    }
+
+    public String getComputationalName() {
+        return computationalName;
+    }
+
+    public void setComputationalName(String computationalName) {
+        this.computationalName = computationalName;
+    }
+
+    public void setResourceUrl(List<ResourceURL> resourceUrl) {
+        this.resourceUrl = resourceUrl;
+    }
+
+    public void setLastActivity(Date lastActivity) {
+        this.lastActivity = lastActivity;
+    }
+
+    public ComputationalStatusDTO withComputationalUrl(List<ResourceURL> resourceUrl) {
+        setResourceUrl(resourceUrl);
+        return this;
+    }
+
+    public ComputationalStatusDTO withComputationalName(String computationalName) {
+        setComputationalName(computationalName);
+        return this;
+    }
+
+    public ComputationalStatusDTO withConfig(List<ClusterConfig> config) {
+        this.config = config;
+        return this;
+    }
+
+    public Date getLastActivity() {
+        return lastActivity;
+    }
+
+    public ComputationalStatusDTO withLastActivity(Date lastActivity) {
+        setLastActivity(lastActivity);
+        return this;
+    }
+
+    public List<ClusterConfig> getConfig() {
+        return config;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("computationalUrl", resourceUrl)
+                .add("computationalId", computationalId)
+                .add("computationalName", computationalName)
+                .add("lastActivity", lastActivity)
+                .add("config", config);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalStopDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalStopDTO.java
new file mode 100644
index 0000000..0a7978b
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalStopDTO.java
@@ -0,0 +1,25 @@
+/*
+ * 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.datalab.dto.computational;
+
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+
+public class ComputationalStopDTO extends ComputationalBase<ComputationalStopDTO> {
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalTerminateDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalTerminateDTO.java
new file mode 100644
index 0000000..2c6051d
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/ComputationalTerminateDTO.java
@@ -0,0 +1,25 @@
+/*
+ * 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.datalab.dto.computational;
+
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+
+public class ComputationalTerminateDTO extends ComputationalBase<ComputationalTerminateDTO> {
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/SparkStandaloneClusterResource.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/SparkStandaloneClusterResource.java
new file mode 100644
index 0000000..f4bbd27
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/SparkStandaloneClusterResource.java
@@ -0,0 +1,62 @@
+/*
+ * 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.datalab.dto.computational;
+
+import com.epam.datalab.dto.ResourceURL;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.hibernate.validator.constraints.NotBlank;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class SparkStandaloneClusterResource extends UserComputationalResource {
+    @NotBlank
+    @JsonProperty("dataengine_instance_count")
+    private String dataEngineInstanceCount;
+
+    @NotBlank
+    @JsonProperty("dataengine_instance_shape")
+    private String dataEngineInstanceShape;
+
+    @Builder
+    public SparkStandaloneClusterResource(String computationalName, String computationalId, String imageName,
+                                          String templateName, String status, Date uptime,
+                                          SchedulerJobDTO schedulerJobData, boolean reuploadKeyRequired,
+                                          String dataEngineInstanceCount, String dataEngineInstanceShape,
+                                          List<ResourceURL> resourceURL, LocalDateTime lastActivity,
+                                          List<ClusterConfig> config, Map<String, String> tags, int totalInstanceCount) {
+        super(computationalName, computationalId, imageName, templateName, status, uptime, schedulerJobData,
+                reuploadKeyRequired, resourceURL, lastActivity, tags, totalInstanceCount);
+        this.dataEngineInstanceCount = dataEngineInstanceCount;
+        this.dataEngineInstanceShape = dataEngineInstanceShape;
+        this.config = config;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/UserComputationalResource.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/UserComputationalResource.java
new file mode 100644
index 0000000..8a52ece
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/UserComputationalResource.java
@@ -0,0 +1,99 @@
+/*
+ * 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.datalab.dto.computational;
+
+import com.epam.datalab.dto.ResourceURL;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+@Data
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UserComputationalResource {
+    @JsonProperty("computational_name")
+    private String computationalName;
+    @JsonProperty("computational_id")
+    private String computationalId;
+    @JsonProperty("image")
+    private String imageName;
+    @JsonProperty("template_name")
+    private String templateName;
+    @JsonProperty
+    private String status;
+    @JsonProperty("up_time")
+    private Date uptime;
+    @JsonProperty("scheduler_data")
+    private SchedulerJobDTO schedulerData;
+    @JsonProperty("reupload_key_required")
+    private boolean reuploadKeyRequired = false;
+    @JsonProperty("computational_url")
+    private List<ResourceURL> resourceUrl;
+    @JsonProperty("last_activity")
+    private LocalDateTime lastActivity;
+    @JsonProperty("master_node_shape")
+    private String masterNodeShape;
+    @JsonProperty("slave_node_shape")
+    private String slaveNodeShape;
+    @JsonProperty("dataengine_instance_shape")
+    private String dataengineShape;
+    @JsonProperty("dataengine_instance_count")
+    private int dataengineInstanceCount;
+    @JsonProperty("instance_id")
+    private String instanceId;
+    @JsonProperty("dataproc_version")
+    private String gcpClusterVersion;
+    @JsonProperty("emr_version")
+    private String awsClusterVersion;
+    private int totalInstanceCount;
+    protected List<ClusterConfig> config;
+    private Map<String, String> tags;
+
+    public UserComputationalResource(String computationalName, String computationalId, String imageName,
+                                     String templateName, String status, Date uptime, SchedulerJobDTO schedulerData,
+                                     boolean reuploadKeyRequired, List<ResourceURL> resourceUrl,
+                                     LocalDateTime lastActivity, Map<String, String> tags, int totalInstanceCount) {
+        this.computationalName = computationalName;
+        this.computationalId = computationalId;
+        this.imageName = imageName;
+        this.templateName = templateName;
+        this.status = status;
+        this.uptime = uptime;
+        this.schedulerData = schedulerData;
+        this.reuploadKeyRequired = reuploadKeyRequired;
+        this.resourceUrl = resourceUrl;
+        this.lastActivity = lastActivity;
+        this.tags = tags;
+        this.totalInstanceCount = totalInstanceCount;
+    }
+
+    public DataEngineType getDataEngineType() {
+        return DataEngineType.fromDockerImageName(imageName);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryActionDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryActionDTO.java
new file mode 100644
index 0000000..c8295cb
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryActionDTO.java
@@ -0,0 +1,71 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+public class ExploratoryActionDTO<T extends ExploratoryActionDTO<?>> extends ExploratoryBaseDTO<T> {
+    @JsonProperty("notebook_instance_name")
+    private String notebookInstanceName;
+
+    @JsonProperty("reupload_key_required")
+    private boolean reuploadKeyRequired;
+
+
+    public boolean isReuploadKeyRequired() {
+        return reuploadKeyRequired;
+    }
+
+    public void setReuploadKeyRequired(boolean reuploadKeyRequired) {
+        this.reuploadKeyRequired = reuploadKeyRequired;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T withReuploadKeyRequired(boolean reuploadKeyRequired) {
+        setReuploadKeyRequired(reuploadKeyRequired);
+        return (T) this;
+    }
+
+    public String getNotebookInstanceName() {
+        return notebookInstanceName;
+    }
+
+    public void setNotebookInstanceName(String notebookInstanceName) {
+        this.notebookInstanceName = notebookInstanceName;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T withNotebookInstanceName(String notebookInstanceName) {
+        setNotebookInstanceName(notebookInstanceName);
+        return (T) this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("notebookInstanceName", notebookInstanceName);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryBaseDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryBaseDTO.java
new file mode 100644
index 0000000..8462e48
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryBaseDTO.java
@@ -0,0 +1,85 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.epam.datalab.dto.ResourceEnvBaseDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+public class ExploratoryBaseDTO<T extends ExploratoryBaseDTO<?>> extends ResourceEnvBaseDTO<T> {
+    @SuppressWarnings("unchecked")
+    private final T self = (T) this;
+    @JsonProperty("notebook_image")
+    private String notebookImage;
+    @JsonProperty("project_name")
+    private String project;
+    @JsonProperty("endpoint_name")
+    private String endpoint;
+
+    public String getNotebookImage() {
+        return notebookImage;
+    }
+
+    public void setNotebookImage(String notebookImage) {
+        this.notebookImage = notebookImage;
+    }
+
+    public T withNotebookImage(String notebookImage) {
+        setNotebookImage(notebookImage);
+        return self;
+    }
+
+    public T withProject(String project) {
+        setProject(project);
+        return self;
+    }
+
+    public T withEndpoint(String endpoint) {
+        setEndpoint(endpoint);
+        return self;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("notebookImage", notebookImage);
+    }
+
+    public String getProject() {
+        return project;
+    }
+
+    public void setProject(String project) {
+        this.project = project;
+    }
+
+    public String getEndpoint() {
+        return endpoint;
+    }
+
+    public void setEndpoint(String endpoint) {
+        this.endpoint = endpoint;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryCheckInactivityAction.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryCheckInactivityAction.java
new file mode 100644
index 0000000..1dc5c7e
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryCheckInactivityAction.java
@@ -0,0 +1,23 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+public class ExploratoryCheckInactivityAction extends ExploratoryActionDTO<ExploratoryCheckInactivityAction> {
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryCreateDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryCreateDTO.java
new file mode 100644
index 0000000..207e5c2
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryCreateDTO.java
@@ -0,0 +1,134 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.List;
+import java.util.Map;
+
+public class ExploratoryCreateDTO<T extends ExploratoryCreateDTO<?>> extends ExploratoryBaseDTO<T> {
+
+    @SuppressWarnings("unchecked")
+    private final T self = (T) this;
+
+    @JsonProperty("git_creds")
+    private List<ExploratoryGitCreds> gitCreds;
+    @JsonProperty("notebook_image_name")
+    private String imageName;
+    @JsonProperty("spark_configurations")
+    private List<ClusterConfig> clusterConfig;
+    @JsonProperty("tags")
+    private Map<String, String> tags;
+    @JsonProperty("endpoint_name")
+    private String endpoint;
+    @JsonProperty("conf_shared_image_enabled")
+    private String sharedImageEnabled;
+
+    /**
+     * Return the list of GIT credentials.
+     */
+    public List<ExploratoryGitCreds> getGitCreds() {
+        return gitCreds;
+    }
+
+    /**
+     * Set the list of GIT credentials.
+     */
+    public void setGitCreds(List<ExploratoryGitCreds> gitCreds) {
+        this.gitCreds = gitCreds;
+    }
+
+    /**
+     * Set the list of GIT credentials and return this object.
+     */
+    public T withGitCreds(List<ExploratoryGitCreds> gitCreds) {
+        setGitCreds(gitCreds);
+        return self;
+    }
+
+    /**
+     * Set the image name and return this object.
+     */
+    public T withImageName(String imageName) {
+        setImageName(imageName);
+        return self;
+    }
+
+    public T withTags(Map<String, String> tags) {
+        this.tags = tags;
+        return self;
+    }
+
+    @Override
+    public T withEndpoint(String endpoint) {
+        this.endpoint = endpoint;
+        return self;
+    }
+
+    public T withSharedImageEnabled(String sharedImageEnabled) {
+        this.sharedImageEnabled = sharedImageEnabled;
+        return self;
+    }
+
+    public String getImageName() {
+        return imageName;
+    }
+
+    public void setImageName(String imageName) {
+        this.imageName = imageName;
+    }
+
+    public T withClusterConfig(List<ClusterConfig> config) {
+        this.clusterConfig = config;
+        return self;
+    }
+
+    @Override
+    public String getEndpoint() {
+        return endpoint;
+    }
+
+    @Override
+    public void setEndpoint(String endpoint) {
+        this.endpoint = endpoint;
+    }
+
+    public String getSharedImageEnabled() {
+        return sharedImageEnabled;
+    }
+
+    public void setSharedImageEnabled(String sharedImageEnabled) {
+        this.sharedImageEnabled = sharedImageEnabled;
+    }
+
+    public List<ClusterConfig> getClusterConfig() {
+        return clusterConfig;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("gitCreds", gitCreds)
+                .add("imageName", imageName);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryGitCreds.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryGitCreds.java
new file mode 100644
index 0000000..2d251a0
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryGitCreds.java
@@ -0,0 +1,193 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import javax.annotation.Nullable;
+import javax.validation.constraints.NotNull;
+
+/**
+ * Describe GIT credentials.
+ */
+public class ExploratoryGitCreds implements Comparable<ExploratoryGitCreds> {
+
+    @NotNull
+    @JsonProperty
+    private String hostname;
+
+    @NotNull
+    @JsonProperty
+    private String username;
+
+    @NotNull
+    @JsonProperty
+    private String email;
+
+    @NotNull
+    @JsonProperty
+    private String login;
+
+    @JsonProperty
+    private String password;
+
+    /**
+     * Return the name of host.
+     */
+    public String getHostname() {
+        return hostname;
+    }
+
+    /**
+     * Set the name of host.
+     */
+    public void setHostname(String hostname) {
+        this.hostname = hostname;
+    }
+
+    /**
+     * Set the name of host.
+     */
+    public ExploratoryGitCreds withHostname(String hostname) {
+        setHostname(hostname);
+        return this;
+    }
+
+    /**
+     * Return the name of user.
+     */
+    public String getUsername() {
+        return username;
+    }
+
+    /**
+     * Set the name of user.
+     */
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    /**
+     * Set the name of user.
+     */
+    public ExploratoryGitCreds withUsername(String username) {
+        setUsername(username);
+        return this;
+    }
+
+    /**
+     * Return the email.
+     */
+    public String getEmail() {
+        return email;
+    }
+
+    /**
+     * Set the email.
+     */
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    /**
+     * Set the email.
+     */
+    public ExploratoryGitCreds withEmail(String email) {
+        setEmail(email);
+        return this;
+    }
+
+    /**
+     * Return the login.
+     */
+    public String getLogin() {
+        return login;
+    }
+
+    /**
+     * Set the login.
+     */
+    public void setLogin(String login) {
+        this.login = login;
+    }
+
+    /**
+     * Set the login.
+     */
+    public ExploratoryGitCreds withLogin(String login) {
+        setLogin(login);
+        return this;
+    }
+
+    /**
+     * Return the password.
+     */
+    public String getPassword() {
+        return password;
+    }
+
+    /**
+     * Set the password.
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    /**
+     * Set the password.
+     */
+    public ExploratoryGitCreds withPassword(String password) {
+        setPassword(password);
+        return this;
+    }
+
+    @Override
+    public int compareTo(@Nullable ExploratoryGitCreds obj) {
+        if (obj == null) {
+            return 1;
+        }
+        return this.hostname.compareToIgnoreCase(obj.hostname);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        return (obj instanceof ExploratoryGitCreds && (this.compareTo((ExploratoryGitCreds) obj) == 0));
+
+    }
+
+    @Override
+    public int hashCode() {
+        return getHostname() != null ? getHostname().hashCode() : 0;
+    }
+
+    @Override
+    public String toString() {
+        return "ExploratoryGitCreds{" +
+                "hostname='" + hostname + '\'' +
+                ", username='" + username + '\'' +
+                ", email='" + email + '\'' +
+                ", login='" + login + '\'' +
+                ", password='" + "***" + '\'' +
+                '}';
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryGitCredsDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryGitCredsDTO.java
new file mode 100644
index 0000000..6a1447b
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryGitCredsDTO.java
@@ -0,0 +1,63 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Stores info about the GIT credentials.
+ */
+public class ExploratoryGitCredsDTO {
+    @JsonProperty("git_creds")
+    private List<ExploratoryGitCreds> gitCreds;
+
+    /**
+     * Return the list of GIT credentials.
+     */
+    public List<ExploratoryGitCreds> getGitCreds() {
+        return gitCreds;
+    }
+
+    /**
+     * Set the list of GIT credentials and check the unique for host names.
+     */
+    public void setGitCreds(List<ExploratoryGitCreds> gitCreds) {
+        if (gitCreds != null) {
+            Collections.sort(gitCreds);
+            for (int i = 1; i < gitCreds.size(); i++) {
+                if (gitCreds.get(i).equals(gitCreds.get(i - 1))) {
+                    throw new IllegalArgumentException("Duplicate found for host name in git credentials: " + gitCreds.get(i).getHostname());
+                }
+            }
+        }
+        this.gitCreds = gitCreds;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("gitCreds", gitCreds)
+                .toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryGitCredsUpdateDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryGitCredsUpdateDTO.java
new file mode 100644
index 0000000..2de41e8
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryGitCredsUpdateDTO.java
@@ -0,0 +1,62 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.List;
+
+/**
+ * Store GIT credentials which should be updated on exploratory.
+ */
+public class ExploratoryGitCredsUpdateDTO extends ExploratoryActionDTO<ExploratoryGitCredsUpdateDTO> {
+    @JsonProperty("git_creds")
+    private List<ExploratoryGitCreds> gitCreds;
+
+    /**
+     * Return the list of GIT credentials.
+     */
+    public List<ExploratoryGitCreds> getGitCreds() {
+        return gitCreds;
+    }
+
+    /**
+     * Set the list of GIT credentials.
+     */
+    public void setGitCreds(List<ExploratoryGitCreds> gitCreds) {
+        this.gitCreds = gitCreds;
+    }
+
+    /**
+     * Set the list of GIT credentials and return this object.
+     */
+    public ExploratoryGitCredsUpdateDTO withGitCreds(List<ExploratoryGitCreds> gitCreds) {
+        setGitCreds(gitCreds);
+        return this;
+    }
+
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("gitCreds", gitCreds);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryImageDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryImageDTO.java
new file mode 100644
index 0000000..2b898c8
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryImageDTO.java
@@ -0,0 +1,72 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+public class ExploratoryImageDTO extends ExploratoryActionDTO<ExploratoryImageDTO> {
+
+    @JsonProperty("notebook_image_name")
+    private String imageName;
+
+    @JsonProperty("tags")
+    private Map<String, String> tags;
+    @JsonProperty("endpoint_name")
+    private String endpoint;
+    @JsonProperty("conf_shared_image_enabled")
+    private String sharedImageEnabled;
+
+    public ExploratoryImageDTO withImageName(String imageName) {
+        this.imageName = imageName;
+        return this;
+    }
+
+    public ExploratoryImageDTO withTags(Map<String, String> tags) {
+        this.tags = tags;
+        return this;
+    }
+
+    @Override
+    public ExploratoryImageDTO withEndpoint(String endpoint) {
+        this.endpoint = endpoint;
+        return this;
+    }
+
+    public ExploratoryImageDTO withSharedImageEnabled(String sharedImageEnabled) {
+        this.sharedImageEnabled = sharedImageEnabled;
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("imageName", imageName);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryReconfigureSparkClusterActionDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryReconfigureSparkClusterActionDTO.java
new file mode 100644
index 0000000..c0f41c7
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryReconfigureSparkClusterActionDTO.java
@@ -0,0 +1,43 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+
+public class ExploratoryReconfigureSparkClusterActionDTO extends ExploratoryActionDTO<ExploratoryReconfigureSparkClusterActionDTO> {
+
+    @JsonProperty("spark_configurations")
+    private List<ClusterConfig> config;
+    @JsonProperty("azure_user_refresh_token")
+    private String azureUserRefreshToken;
+
+    public ExploratoryReconfigureSparkClusterActionDTO withConfig(List<ClusterConfig> config) {
+        this.config = config;
+        return this;
+    }
+
+    public ExploratoryReconfigureSparkClusterActionDTO withAzureUserRefreshToken(String azureUserRefreshToken) {
+        this.azureUserRefreshToken = azureUserRefreshToken;
+        return this;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryStatusDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryStatusDTO.java
new file mode 100644
index 0000000..cc47e46
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ExploratoryStatusDTO.java
@@ -0,0 +1,128 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.epam.datalab.dto.ResourceURL;
+import com.epam.datalab.dto.StatusEnvBaseDTO;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.Date;
+import java.util.List;
+
+public class ExploratoryStatusDTO extends StatusEnvBaseDTO<ExploratoryStatusDTO> {
+    @JsonProperty("exploratory_url")
+    private List<ResourceURL> resourceUrl;
+    @JsonProperty("exploratory_user")
+    private String exploratoryUser;
+    @JsonProperty("exploratory_pass")
+    private String exploratoryPassword;
+    @JsonProperty("private_ip")
+    private String privateIp;
+    @JsonProperty("last_activity")
+    private Date lastActivity;
+    @JsonProperty
+    private List<ClusterConfig> config;
+
+    public String getPrivateIp() {
+        return privateIp;
+    }
+
+    public void setPrivateIp(String privateIp) {
+        this.privateIp = privateIp;
+    }
+
+    public ExploratoryStatusDTO withPrivateIp(String privateIp) {
+        setPrivateIp(privateIp);
+        return this;
+    }
+
+    public List<ResourceURL> getResourceUrl() {
+        return resourceUrl;
+    }
+
+    public void setResourceUrl(List<ResourceURL> resourceUrl) {
+        this.resourceUrl = resourceUrl;
+    }
+
+    public ExploratoryStatusDTO withExploratoryUrl(List<ResourceURL> resourceUrl) {
+        setResourceUrl(resourceUrl);
+        return this;
+    }
+
+    public String getExploratoryUser() {
+        return exploratoryUser;
+    }
+
+    public void setExploratoryUser(String exploratoryUser) {
+        this.exploratoryUser = exploratoryUser;
+    }
+
+    public ExploratoryStatusDTO withExploratoryUser(String exploratoryUser) {
+        setExploratoryUser(exploratoryUser);
+        return this;
+    }
+
+    public String getExploratoryPassword() {
+        return exploratoryPassword;
+    }
+
+    public void setExploratoryPassword(String exploratoryPassword) {
+        this.exploratoryPassword = exploratoryPassword;
+    }
+
+    public ExploratoryStatusDTO withExploratoryPassword(String exploratoryPassword) {
+        setExploratoryPassword(exploratoryPassword);
+        return this;
+    }
+
+    public ExploratoryStatusDTO withConfig(List<ClusterConfig> config) {
+        this.config = config;
+        return this;
+    }
+
+    public List<ClusterConfig> getConfig() {
+        return config;
+    }
+
+    public ExploratoryStatusDTO withLastActivity(Date lastActivity) {
+        this.lastActivity = lastActivity;
+        return this;
+    }
+
+    public Date getLastActivity() {
+        return lastActivity;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("exploratoryUrl", resourceUrl)
+                .add("exploratoryUser", exploratoryUser)
+                .add("exploratoryPassword", exploratoryPassword)
+                .add("config", config);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageCreateStatusDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageCreateStatusDTO.java
new file mode 100644
index 0000000..a175012
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageCreateStatusDTO.java
@@ -0,0 +1,74 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.epam.datalab.dto.StatusBaseDTO;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+@Data
+public class ImageCreateStatusDTO extends StatusBaseDTO<ImageCreateStatusDTO> {
+
+    private ImageCreateDTO imageCreateDTO;
+    private String name;
+    private String exploratoryName;
+    private String project;
+    private String endpoint;
+
+    public ImageCreateStatusDTO withImageCreateDto(ImageCreateDTO imageCreateDto) {
+        setImageCreateDTO(imageCreateDto);
+        return this;
+    }
+
+    public ImageCreateStatusDTO withoutImageCreateDto() {
+        setImageCreateDTO(new ImageCreateDTO());
+        return this;
+    }
+
+    @Data
+    @ToString
+    @JsonIgnoreProperties(ignoreUnknown = true)
+    @NoArgsConstructor
+    public static class ImageCreateDTO {
+        private String externalName;
+        private String fullName;
+        private String user;
+        private String application;
+        private ImageStatus status;
+        private String ip;
+
+        @JsonCreator
+        public ImageCreateDTO(@JsonProperty("notebook_image_name") String externalName,
+                              @JsonProperty("full_image_name") String fullName,
+                              @JsonProperty("user_name") String user, @JsonProperty("application") String application,
+                              @JsonProperty("status") ImageStatus status, @JsonProperty("ip") String ip) {
+            this.externalName = externalName;
+            this.fullName = fullName;
+            this.user = user;
+            this.application = application;
+            this.status = status;
+            this.ip = ip;
+        }
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageStatus.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageStatus.java
new file mode 100644
index 0000000..90e3edf
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageStatus.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.datalab.dto.exploratory;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+import java.util.Arrays;
+
+public enum ImageStatus {
+    CREATING,
+    CREATED,
+    FAILED;
+
+    @JsonCreator
+    public static ImageStatus fromValue(final String status) {
+        return Arrays.stream(ImageStatus.values())
+                .filter(s -> s.name().equalsIgnoreCase(status))
+                .findAny()
+                .orElseThrow(() -> new IllegalArgumentException(String.format("Wrong value for image status: %s",
+                        status)));
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibInstallDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibInstallDTO.java
new file mode 100644
index 0000000..9cec6cd
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibInstallDTO.java
@@ -0,0 +1,85 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * Stores info about libraries.
+ */
+@Data
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class LibInstallDTO {
+    @JsonProperty
+    private String group;
+
+    @JsonProperty
+    private String name;
+
+    @JsonProperty
+    private String version;
+
+    @JsonProperty
+    private String status;
+
+    @JsonProperty("error_message")
+    private String errorMessage;
+
+    @JsonProperty
+    private boolean override;
+
+    @JsonProperty("available_versions")
+    private List<String> availableVersions;
+
+    @JsonProperty("add_pkgs")
+    private List<String> addedPackages;
+
+    public LibInstallDTO(String group, String name, String version) {
+        this.group = group;
+        this.name = name;
+        this.version = version;
+    }
+
+    public LibInstallDTO withName(String name) {
+        setName(name);
+        return this;
+    }
+
+    public LibInstallDTO withStatus(String status) {
+        setStatus(status);
+        return this;
+    }
+
+    public LibInstallDTO withErrorMessage(String errorMessage) {
+        setErrorMessage(errorMessage);
+        return this;
+    }
+
+    public LibInstallDTO withAddedPackages(List<String> addedPackages) {
+        setAddedPackages(addedPackages);
+        return this;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibInstallStatusDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibInstallStatusDTO.java
new file mode 100644
index 0000000..319f9d9
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibInstallStatusDTO.java
@@ -0,0 +1,57 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.epam.datalab.dto.StatusEnvBaseDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class LibInstallStatusDTO extends StatusEnvBaseDTO<LibInstallStatusDTO> {
+    @JsonProperty
+    private List<LibInstallDTO> libs;
+
+    @JsonProperty
+    private String computationalName;
+
+
+    public LibInstallStatusDTO withLibs(List<LibInstallDTO> libs) {
+        setLibs(libs);
+        return this;
+    }
+
+    public LibInstallStatusDTO withComputationalName(String computationalName) {
+        setComputationalName(computationalName);
+        return this;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("libs", libs)
+                .add("computationalName", computationalName);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibListStatusDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibListStatusDTO.java
new file mode 100644
index 0000000..402e03b
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibListStatusDTO.java
@@ -0,0 +1,63 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.epam.datalab.dto.StatusBaseDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Stores the info about group libraries.
+ */
+@Getter
+@Setter
+public class LibListStatusDTO extends StatusBaseDTO<LibListStatusDTO> {
+
+    @JsonProperty
+    private String libs;
+
+    @JsonProperty
+    private String group;
+
+    /**
+     * Set the list of libraries and return this object
+     */
+    public LibListStatusDTO withLibs(String libs) {
+        setLibs(libs);
+        return this;
+    }
+
+    /**
+     * Set the name of group and return this object
+     */
+    public LibListStatusDTO withGroup(String group) {
+        setGroup(group);
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("group", group)
+                .add("libs", (libs != null) ? "..." : null);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibStatus.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibStatus.java
new file mode 100644
index 0000000..104ff77
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibStatus.java
@@ -0,0 +1,49 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+/**
+ * Statuses for the libraries.
+ */
+public enum LibStatus {
+    INSTALLING,
+    INSTALLED,
+    INVALID_VERSION,
+    INVALID_NAME,
+    INSTALLATION_ERROR;
+
+    @JsonCreator
+    public static LibStatus of(String status) {
+        if (status != null) {
+            for (LibStatus uis : LibStatus.values()) {
+                if (status.equalsIgnoreCase(uis.toString())) {
+                    return uis;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString().toLowerCase();
+    }
+}
\ No newline at end of file
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibraryInstallDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibraryInstallDTO.java
new file mode 100644
index 0000000..329a0ff
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/LibraryInstallDTO.java
@@ -0,0 +1,67 @@
+/*
+ * 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.datalab.dto.exploratory;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.util.List;
+
+/**
+ * Store info about libraries which user should be installed.
+ */
+@Getter
+@Setter
+@ToString(callSuper = true)
+public class LibraryInstallDTO extends ExploratoryActionDTO<LibraryInstallDTO> {
+    @JsonProperty("libs")
+    private List<LibInstallDTO> libs;
+
+    @JsonProperty("computational_id")
+    private String computationalId;
+
+    @JsonProperty("computational_image")
+    private String computationalImage;
+
+    @JsonProperty("computational_name")
+    private String computationalName;
+
+    public LibraryInstallDTO withLibs(List<LibInstallDTO> libs) {
+        setLibs(libs);
+        return this;
+    }
+
+    public LibraryInstallDTO withComputationalId(String computationalId) {
+        setComputationalId(computationalId);
+        return this;
+    }
+
+    public LibraryInstallDTO withComputationalImage(String computationalImage) {
+        setComputationalImage(computationalImage);
+        return this;
+    }
+
+    public LibraryInstallDTO withComputationalName(String computationalName) {
+        setComputationalName(computationalName);
+        return this;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/GcpCloudSettings.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/GcpCloudSettings.java
new file mode 100644
index 0000000..8d621f7
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/GcpCloudSettings.java
@@ -0,0 +1,96 @@
+/*
+ * 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.datalab.dto.gcp;
+
+import com.epam.datalab.dto.base.CloudSettings;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@Builder
+@AllArgsConstructor
+public class GcpCloudSettings extends CloudSettings {
+
+    @JsonProperty("gcp_iam_user")
+    private String gcpIamUser;
+    @JsonProperty("ldap_hostname")
+    protected String ldapHost;
+    @JsonProperty("ldap_dn")
+    protected String ldapDn;
+    @JsonProperty("ldap_ou")
+    protected String ldapOu;
+    @JsonProperty("ldap_service_username")
+    protected String ldapUser;
+    @JsonProperty("ldap_service_password")
+    protected String ldapPassword;
+    @JsonProperty("conf_os_family")
+    protected String os;
+    @JsonProperty("conf_cloud_provider")
+    protected String cloud;
+    @JsonProperty("conf_service_base_name")
+    protected String sbn;
+    @JsonProperty("conf_key_dir")
+    protected String confKeyDir;
+    @JsonProperty("gcp_project_id")
+    protected String projectId;
+    @JsonProperty("gcp_vpc_name")
+    protected String vpcName;
+    @JsonProperty("gcp_subnet_name")
+    protected String subnetName;
+    @JsonProperty("gcp_zone")
+    protected String zone;
+    @JsonProperty("gcp_region")
+    protected String region;
+    @JsonProperty("conf_image_enabled")
+    private String imageEnabled;
+    @JsonProperty("conf_stepcerts_enabled")
+    private String stepCertsEnabled;
+    @JsonProperty("conf_stepcerts_root_ca")
+    private String stepCertsRootCA;
+    @JsonProperty("conf_stepcerts_kid")
+    private String stepCertsKid;
+    @JsonProperty("conf_stepcerts_kid_password")
+    private String stepCertsKidPassword;
+    @JsonProperty("conf_stepcerts_ca_url")
+    private String stepCertsCAURL;
+    @JsonProperty("keycloak_auth_server_url")
+    private String keycloakAuthServerUrl;
+    @JsonProperty("keycloak_realm_name")
+    private String keycloakRealmName;
+    @JsonProperty("keycloak_user")
+    private String keycloakUser;
+    @JsonProperty("keycloak_user_password")
+    private String keycloakUserPassword;
+
+    @Override
+    @JsonIgnore
+    public String getIamUser() {
+        return gcpIamUser;
+    }
+}
\ No newline at end of file
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/auth/GcpOauth2AuthorizationCodeResponse.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/auth/GcpOauth2AuthorizationCodeResponse.java
new file mode 100644
index 0000000..28c115a
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/auth/GcpOauth2AuthorizationCodeResponse.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab.dto.gcp.auth;
+
+import lombok.Data;
+
+@Data
+public class GcpOauth2AuthorizationCodeResponse {
+    private final String code;
+    private final String state;
+    private final String errorMessage;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/computational/ComputationalCreateGcp.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/computational/ComputationalCreateGcp.java
new file mode 100644
index 0000000..7cbcfac
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/computational/ComputationalCreateGcp.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.datalab.dto.gcp.computational;
+
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+public class ComputationalCreateGcp extends ComputationalBase<ComputationalCreateGcp> {
+    @JsonProperty("dataproc_master_count")
+    private String masterInstanceCount;
+    @JsonProperty("dataproc_slave_count")
+    private String slaveInstanceCount;
+    @JsonProperty("dataproc_master_instance_type")
+    private String masterInstanceType;
+    @JsonProperty("dataproc_slave_instance_type")
+    private String slaveInstanceType;
+    @JsonProperty("dataproc_preemptible_count")
+    private String preemptibleCount;
+    @JsonProperty("dataproc_version")
+    private String version;
+    @JsonProperty("conf_shared_image_enabled")
+    private String sharedImageEnabled;
+
+    public ComputationalCreateGcp withMasterInstanceCount(String masterInstanceCount) {
+        this.masterInstanceCount = masterInstanceCount;
+        return this;
+    }
+
+    public ComputationalCreateGcp withSlaveInstanceCount(String slaveInstanceCount) {
+        this.slaveInstanceCount = slaveInstanceCount;
+        return this;
+    }
+
+    public ComputationalCreateGcp withMasterInstanceType(String masterInstanceType) {
+        this.masterInstanceType = masterInstanceType;
+        return this;
+    }
+
+    public ComputationalCreateGcp withSlaveInstanceType(String slaveInstanceType) {
+        this.slaveInstanceType = slaveInstanceType;
+        return this;
+    }
+
+    public ComputationalCreateGcp withPreemptibleCount(String preemptibleCount) {
+        this.preemptibleCount = preemptibleCount;
+        return this;
+    }
+
+    public ComputationalCreateGcp withVersion(String version) {
+        this.version = version;
+        return this;
+    }
+
+    public String getSharedImageEnabled() {
+        return sharedImageEnabled;
+    }
+
+    public void setSharedImageEnabled(String sharedImageEnabled) {
+        this.sharedImageEnabled = sharedImageEnabled;
+    }
+
+    public ComputationalCreateGcp withSharedImageEnabled(String sharedImageEnabled) {
+        setSharedImageEnabled(sharedImageEnabled);
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("version", version)
+                .add("masterInstanceType", masterInstanceType)
+                .add("slaveInstanceType", slaveInstanceType)
+                .add("masterInstanceCount", masterInstanceCount)
+                .add("slaveInstanceCount", slaveInstanceCount)
+                .add("preemptibleCount", preemptibleCount);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/computational/GcpComputationalResource.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/computational/GcpComputationalResource.java
new file mode 100644
index 0000000..21f7672
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/computational/GcpComputationalResource.java
@@ -0,0 +1,77 @@
+/*
+ * 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.datalab.dto.gcp.computational;
+
+import com.epam.datalab.dto.ResourceURL;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Stores info about the user's computational resources for notebook.
+ */
+@ToString(callSuper = true)
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public class GcpComputationalResource extends UserComputationalResource {
+
+    @JsonProperty("instance_id")
+    private String instanceId;
+    @JsonProperty("master_node_shape")
+    private String masterShape;
+    @JsonProperty("slave_node_shape")
+    private String slaveShape;
+    @JsonProperty("total_slave_instance_number")
+    private String slaveNumber;
+    @JsonProperty("total_master_instance_number")
+    private String masterNumber;
+    @JsonProperty("total_preemptible_number")
+    private String preemptibleNumber;
+    @JsonProperty("dataproc_version")
+    private String version;
+
+    @Builder
+    public GcpComputationalResource(String computationalName, String computationalId, String imageName,
+                                    String templateName, String status, Date uptime,
+                                    SchedulerJobDTO schedulerJobData, boolean reuploadKeyRequired,
+                                    String instanceId, String masterShape, String slaveShape, String slaveNumber,
+                                    String masterNumber, String preemptibleNumber, String version,
+                                    List<ResourceURL> resourceURL, LocalDateTime lastActivity,
+                                    Map<String, String> tags, int totalInstanceCount) {
+        super(computationalName, computationalId, imageName, templateName, status, uptime, schedulerJobData,
+                reuploadKeyRequired, resourceURL, lastActivity, tags, totalInstanceCount);
+        this.instanceId = instanceId;
+        this.masterShape = masterShape;
+        this.slaveShape = slaveShape;
+        this.slaveNumber = slaveNumber;
+        this.masterNumber = masterNumber;
+        this.version = version;
+        this.preemptibleNumber = preemptibleNumber;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/computational/GcpComputationalTerminateDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/computational/GcpComputationalTerminateDTO.java
new file mode 100644
index 0000000..83b20f9
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/computational/GcpComputationalTerminateDTO.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.datalab.dto.gcp.computational;
+
+import com.epam.datalab.dto.computational.ComputationalTerminateDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+public class GcpComputationalTerminateDTO extends ComputationalTerminateDTO {
+
+    @JsonProperty("dataproc_cluster_name")
+    private String clusterName;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/computational/SparkComputationalCreateGcp.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/computational/SparkComputationalCreateGcp.java
new file mode 100644
index 0000000..90bd51e
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/computational/SparkComputationalCreateGcp.java
@@ -0,0 +1,81 @@
+/*
+ * 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.datalab.dto.gcp.computational;
+
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+import java.util.List;
+
+
+public class SparkComputationalCreateGcp extends ComputationalBase<SparkComputationalCreateGcp> {
+
+    @JsonProperty("dataengine_instance_count")
+    private String dataEngineInstanceCount;
+    @JsonProperty("gcp_dataengine_slave_size")
+    private String dataEngineSlaveSize;
+    @JsonProperty("gcp_dataengine_master_size")
+    private String dataEngineMasterSize;
+    @JsonProperty("spark_configurations")
+    private List<ClusterConfig> config;
+    @JsonProperty("conf_shared_image_enabled")
+    private String sharedImageEnabled;
+
+    public SparkComputationalCreateGcp withDataEngineInstanceCount(String dataEngineInstanceCount) {
+        this.dataEngineInstanceCount = dataEngineInstanceCount;
+        return this;
+    }
+
+    public SparkComputationalCreateGcp withDataEngineSlaveSize(String dataEngineSlaveSize) {
+        this.dataEngineSlaveSize = dataEngineSlaveSize;
+        return this;
+    }
+
+    public SparkComputationalCreateGcp withDataEngineMasterSize(String dataEngineMasterSize) {
+        this.dataEngineMasterSize = dataEngineMasterSize;
+        return this;
+    }
+
+    public SparkComputationalCreateGcp withConfig(List<ClusterConfig> config) {
+        this.config = config;
+        return this;
+    }
+
+    public SparkComputationalCreateGcp withSharedImageEnabled(String sharedImageEnabled) {
+        this.sharedImageEnabled = sharedImageEnabled;
+        return this;
+    }
+
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("dataEngineInstanceCount", dataEngineInstanceCount)
+                .add("dataEngineSlaveSize", dataEngineSlaveSize)
+                .add("dataEngineMasterSize", dataEngineMasterSize);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/edge/EdgeCreateGcp.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/edge/EdgeCreateGcp.java
new file mode 100644
index 0000000..6df52f3
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/edge/EdgeCreateGcp.java
@@ -0,0 +1,25 @@
+/*
+ * 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.datalab.dto.gcp.edge;
+
+import com.epam.datalab.dto.ResourceSysBaseDTO;
+
+public class EdgeCreateGcp extends ResourceSysBaseDTO<EdgeCreateGcp> {
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/edge/EdgeInfoGcp.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/edge/EdgeInfoGcp.java
new file mode 100644
index 0000000..490ce54
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/edge/EdgeInfoGcp.java
@@ -0,0 +1,40 @@
+/*
+ * 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.datalab.dto.gcp.edge;
+
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class EdgeInfoGcp extends EdgeInfo {
+    @JsonProperty("user_own_bucket_name")
+    private String userOwnBucketName;
+    @JsonProperty("shared_bucket_name")
+    private String sharedBucketName;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/exploratory/ExploratoryCreateGcp.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/exploratory/ExploratoryCreateGcp.java
new file mode 100644
index 0000000..a18e1db
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/exploratory/ExploratoryCreateGcp.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab.dto.gcp.exploratory;
+
+import com.epam.datalab.dto.exploratory.ExploratoryCreateDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+public class ExploratoryCreateGcp extends ExploratoryCreateDTO<ExploratoryCreateGcp> {
+    @JsonProperty("gcp_notebook_instance_size")
+    private String notebookInstanceSize;
+
+    public String getNotebookInstanceSize() {
+        return notebookInstanceSize;
+    }
+
+    public void setNotebookInstanceSize(String notebookInstanceSize) {
+        this.notebookInstanceSize = notebookInstanceSize;
+    }
+
+    public ExploratoryCreateGcp withNotebookInstanceType(String notebookInstanceType) {
+        setNotebookInstanceSize(notebookInstanceType);
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("notebookInstanceSize", notebookInstanceSize);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/keyload/UploadFileGcp.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/keyload/UploadFileGcp.java
new file mode 100644
index 0000000..d10ea83
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/gcp/keyload/UploadFileGcp.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.dto.gcp.keyload;
+
+import com.epam.datalab.dto.base.keyload.UploadFile;
+import com.epam.datalab.dto.gcp.edge.EdgeCreateGcp;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class UploadFileGcp extends UploadFile {
+    @JsonProperty
+    private final EdgeCreateGcp edge;
+
+    @JsonCreator
+    public UploadFileGcp(@JsonProperty("edge") EdgeCreateGcp edge, @JsonProperty("content") String content) {
+        super(content);
+        this.edge = edge;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ApplicationDto.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ApplicationDto.java
new file mode 100644
index 0000000..ad096fe
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ApplicationDto.java
@@ -0,0 +1,85 @@
+/*
+ * 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.datalab.dto.imagemetadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+
+import java.util.Objects;
+
+public class ApplicationDto {
+    @JsonProperty("Version")
+    private String version;
+    @JsonProperty("Name")
+    private String name;
+
+    public ApplicationDto() {
+    }
+
+
+    public ApplicationDto(String version, String name) {
+        this.version = version;
+        this.name = name;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        ApplicationDto that = (ApplicationDto) o;
+
+        if (version != null ? !version.equals(that.version) : that.version != null) {
+            return false;
+        }
+        return name != null ? name.equals(that.name) : that.name == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(version, name);
+    }
+
+    @Override
+    public String toString() {
+        return ReflectionToStringBuilder.toString(this);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ComputationalMetadataDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ComputationalMetadataDTO.java
new file mode 100644
index 0000000..626e70e
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ComputationalMetadataDTO.java
@@ -0,0 +1,53 @@
+/*
+ * 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.datalab.dto.imagemetadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class ComputationalMetadataDTO extends ImageMetadataDTO {
+    @JsonProperty
+    protected String image;
+    @JsonProperty("template_name")
+    private String templateName;
+    @JsonProperty
+    private String description;
+    @JsonProperty("environment_type")
+    private String type;
+    @JsonProperty
+    private List<TemplateDTO> templates;
+    @JsonProperty("request_id")
+    private String requestId;
+    @JsonProperty(value = "computation_resources_shapes")
+    private Map<String, List<ComputationalResourceShapeDto>> computationResourceShapes;
+
+    public ComputationalMetadataDTO(String imageName) {
+        this.image = imageName;
+        setImageType(ImageType.COMPUTATIONAL);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ComputationalResourceShapeDto.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ComputationalResourceShapeDto.java
new file mode 100644
index 0000000..c78a5eb
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ComputationalResourceShapeDto.java
@@ -0,0 +1,114 @@
+/*
+ * 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.datalab.dto.imagemetadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+
+public class ComputationalResourceShapeDto {
+    @JsonProperty("Type")
+    private String type;
+    @JsonProperty("Size")
+    private String size;
+    @JsonProperty("Description")
+    private String description;
+    @JsonProperty("Ram")
+    private String ram;
+    @JsonProperty("Cpu")
+    private int cpu;
+    @JsonProperty("Spot")
+    private boolean spot = false;
+
+    @JsonProperty("SpotPctPrice")
+    private int spotPctPrice = 70;
+
+
+    public ComputationalResourceShapeDto() {
+    }
+
+    public ComputationalResourceShapeDto(String type, String size, String description, String ram, int cpu) {
+        this.type = type;
+        this.size = size;
+        this.description = description;
+        this.ram = ram;
+        this.cpu = cpu;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getSize() {
+        return size;
+    }
+
+    public void setSize(String size) {
+        this.size = size;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getRam() {
+        return ram;
+    }
+
+    public void setRam(String ram) {
+        this.ram = ram;
+    }
+
+    public int getCpu() {
+        return cpu;
+    }
+
+    public void setCpu(int cpu) {
+        this.cpu = cpu;
+    }
+
+    public boolean isSpot() {
+        return spot;
+    }
+
+    public void setSpot(boolean spot) {
+        this.spot = spot;
+    }
+
+    public int getSpotPctPrice() {
+        return spotPctPrice;
+    }
+
+    public void setSpotPctPrice(int spotPctPrice) {
+        this.spotPctPrice = spotPctPrice;
+    }
+
+    @Override
+    public String toString() {
+        return ReflectionToStringBuilder.toString(this);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ExploratoryEnvironmentVersion.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ExploratoryEnvironmentVersion.java
new file mode 100644
index 0000000..0c8f0e0
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ExploratoryEnvironmentVersion.java
@@ -0,0 +1,94 @@
+/*
+ * 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.datalab.dto.imagemetadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+
+public class ExploratoryEnvironmentVersion {
+    @JsonProperty("template_name")
+    private String templateName;
+    @JsonProperty
+    private String description;
+    @JsonProperty("environment_type")
+    private String type;
+    @JsonProperty("version")
+    private String version;
+    @JsonProperty("vendor")
+    private String vendor;
+
+    public ExploratoryEnvironmentVersion() {
+    }
+
+    public ExploratoryEnvironmentVersion(String templateName, String description, String type, String version,
+                                         String vendor) {
+        this.templateName = templateName;
+        this.description = description;
+        this.type = type;
+        this.version = version;
+        this.vendor = vendor;
+    }
+
+    public String getTemplateName() {
+        return templateName;
+    }
+
+    public void setTemplateName(String templateName) {
+        this.templateName = templateName;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getVendor() {
+        return vendor;
+    }
+
+    public void setVendor(String vendor) {
+        this.vendor = vendor;
+    }
+
+    @Override
+    public String toString() {
+        return ReflectionToStringBuilder.toString(this);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ExploratoryMetadataDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ExploratoryMetadataDTO.java
new file mode 100644
index 0000000..3c961c2
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ExploratoryMetadataDTO.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab.dto.imagemetadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.util.HashMap;
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class ExploratoryMetadataDTO extends ImageMetadataDTO {
+    @JsonProperty
+    protected String image;
+    @JsonProperty("exploratory_environment_versions")
+    private List<ExploratoryEnvironmentVersion> exploratoryEnvironmentVersions;
+    @JsonProperty("exploratory_environment_shapes")
+    private HashMap<String, List<ComputationalResourceShapeDto>> exploratoryEnvironmentShapes;
+    @JsonProperty("request_id")
+    private String requestId;
+
+    public ExploratoryMetadataDTO(String imageName) {
+        this.image = imageName;
+        setImageType(ImageType.EXPLORATORY);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ImageMetadataDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ImageMetadataDTO.java
new file mode 100644
index 0000000..33d508a
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ImageMetadataDTO.java
@@ -0,0 +1,51 @@
+/*
+ * 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.datalab.dto.imagemetadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+
+/**
+ * Common parent for metadata DTO. Holds type information during
+ * runtime to make life easier when working with collection of metadatas or
+ * filtering by type. Shouldnt be used to hold common attributes for upstream
+ * hierarchy as it will requite type information to be serialized within json
+ * which is not we really want.
+ */
+public abstract class ImageMetadataDTO {
+    @JsonProperty("image_type")
+    private ImageType imageType;
+
+    public ImageType getImageType() {
+        return imageType;
+    }
+
+    public void setImageType(ImageType imageType) {
+        this.imageType = imageType;
+    }
+
+    public abstract void setImage(String image);
+
+    @Override
+    public String toString() {
+        return ReflectionToStringBuilder.toString(this);
+    }
+
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ImageType.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ImageType.java
new file mode 100644
index 0000000..3175491
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/ImageType.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.dto.imagemetadata;
+
+public enum ImageType {
+    COMPUTATIONAL("computational"),
+    EXPLORATORY("exploratory");
+
+    private String type;
+
+    ImageType(String type) {
+        this.type = type;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public static ImageType of(String type) {
+        if (type != null) {
+            for (ImageType value : ImageType.values()) {
+                if (type.equalsIgnoreCase(value.toString())) {
+                    return value;
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/TemplateDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/TemplateDTO.java
new file mode 100644
index 0000000..746ab8a
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/imagemetadata/TemplateDTO.java
@@ -0,0 +1,84 @@
+/*
+ * 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.datalab.dto.imagemetadata;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+
+import java.util.List;
+import java.util.Objects;
+
+public class TemplateDTO {
+    @JsonProperty
+    private String version;
+    @JsonProperty
+    private List<ApplicationDto> applications;
+
+    public TemplateDTO() {
+    }
+
+    public TemplateDTO(String version) {
+        this.version = version;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public List<ApplicationDto> getApplications() {
+        return applications;
+    }
+
+    public void setApplications(List<ApplicationDto> applications) {
+        this.applications = applications;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        TemplateDTO that = (TemplateDTO) o;
+
+        if (version != null ? !version.equals(that.version) : that.version != null) {
+            return false;
+        }
+        return applications != null ? applications.equals(that.applications) : that.applications == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(version, applications);
+    }
+
+    @Override
+    public String toString() {
+        return ReflectionToStringBuilder.toString(this);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/keyload/KeyLoadStatus.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/keyload/KeyLoadStatus.java
new file mode 100644
index 0000000..12f3683
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/keyload/KeyLoadStatus.java
@@ -0,0 +1,60 @@
+/*
+ * 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.datalab.dto.keyload;
+
+import javax.ws.rs.core.Response;
+import java.util.Arrays;
+
+public enum KeyLoadStatus {
+    NONE("none", null, Response.Status.NOT_FOUND),
+    NEW("new", null, Response.Status.ACCEPTED),
+    SUCCESS("success", "ok", Response.Status.OK),
+    ERROR("error", "err", Response.Status.INTERNAL_SERVER_ERROR);
+
+    private String status;
+    private String value;
+    private Response.Status httpStatus;
+
+    KeyLoadStatus(String status, String value, Response.Status httpStatus) {
+        this.status = status;
+        this.value = value;
+        this.httpStatus = httpStatus;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public Response.Status getHttpStatus() {
+        return httpStatus;
+    }
+
+    public static boolean isSuccess(String value) {
+        return SUCCESS.value.equals(value);
+    }
+
+    public static String getStatus(boolean successed) {
+        return successed ? SUCCESS.status : ERROR.status;
+    }
+
+    public static KeyLoadStatus findByStatus(String status) {
+        return Arrays.stream(values()).reduce(NONE, (result, next) -> next.status.equalsIgnoreCase(status) ? next : result);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/keyload/UserKeyDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/keyload/UserKeyDTO.java
new file mode 100644
index 0000000..f17d50e
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/keyload/UserKeyDTO.java
@@ -0,0 +1,58 @@
+/*
+ * 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.datalab.dto.keyload;
+
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UserKeyDTO {
+    @JsonProperty
+    private String content;
+    @JsonProperty
+    private String status;
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public UserKeyDTO withContent(String content) {
+        setContent(content);
+        return this;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public UserKeyDTO withStatus(String status) {
+        setStatus(status);
+        return this;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/project/ProjectActionDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/project/ProjectActionDTO.java
new file mode 100644
index 0000000..64ccc21
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/project/ProjectActionDTO.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab.dto.project;
+
+import com.epam.datalab.dto.ResourceBaseDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class ProjectActionDTO extends ResourceBaseDTO<ProjectActionDTO> {
+    @JsonProperty("project_name")
+    private final String name;
+    @JsonProperty("endpoint_name")
+    private final String endpoint;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/project/ProjectCreateDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/project/ProjectCreateDTO.java
new file mode 100644
index 0000000..09cbd46
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/project/ProjectCreateDTO.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab.dto.project;
+
+import com.epam.datalab.dto.ResourceBaseDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class ProjectCreateDTO extends ResourceBaseDTO<ProjectCreateDTO> {
+    private final String key;
+    @JsonProperty("project_name")
+    private final String name;
+    @JsonProperty("project_tag")
+    private final String tag;
+    @JsonProperty("endpoint_name")
+    private final String endpoint;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/reuploadkey/ReuploadKeyCallbackDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/reuploadkey/ReuploadKeyCallbackDTO.java
new file mode 100644
index 0000000..bb1aca7
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/reuploadkey/ReuploadKeyCallbackDTO.java
@@ -0,0 +1,64 @@
+/*
+ * 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.datalab.dto.reuploadkey;
+
+import com.epam.datalab.dto.ResourceSysBaseDTO;
+import com.epam.datalab.model.ResourceData;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import lombok.Getter;
+
+@Getter
+public class ReuploadKeyCallbackDTO extends ResourceSysBaseDTO<ReuploadKeyCallbackDTO> {
+
+    @JsonProperty
+    private ResourceData resource;
+
+    @JsonProperty("resource_id")
+    private String resourceId;
+
+    @JsonProperty
+    private String id;
+
+
+    public ReuploadKeyCallbackDTO withResource(ResourceData resource) {
+        this.resource = resource;
+        return this;
+    }
+
+    public ReuploadKeyCallbackDTO withId(String id) {
+        this.id = id;
+        return this;
+    }
+
+    public ReuploadKeyCallbackDTO withResourceId(String resourceId) {
+        this.resourceId = resourceId;
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("resource", resource)
+                .add("resource_id", resourceId)
+                .add("id", id);
+    }
+}
+
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/reuploadkey/ReuploadKeyDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/reuploadkey/ReuploadKeyDTO.java
new file mode 100644
index 0000000..478f408
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/reuploadkey/ReuploadKeyDTO.java
@@ -0,0 +1,56 @@
+/*
+ * 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.datalab.dto.reuploadkey;
+
+import com.epam.datalab.dto.ResourceSysBaseDTO;
+import com.epam.datalab.model.ResourceData;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+public class ReuploadKeyDTO extends ResourceSysBaseDTO<ReuploadKeyDTO> {
+
+    @JsonProperty
+    private String content;
+
+    @JsonProperty
+    private List<ResourceData> resources;
+
+    @JsonProperty
+    private String id;
+
+
+    public ReuploadKeyDTO withContent(String content) {
+        this.content = content;
+        return this;
+    }
+
+    public ReuploadKeyDTO withResources(List<ResourceData> resources) {
+        this.resources = resources;
+        return this;
+    }
+
+    public ReuploadKeyDTO withId(String id) {
+        this.id = id;
+        return this;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/reuploadkey/ReuploadKeyStatus.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/reuploadkey/ReuploadKeyStatus.java
new file mode 100644
index 0000000..aa44103
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/reuploadkey/ReuploadKeyStatus.java
@@ -0,0 +1,49 @@
+/*
+ * 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.datalab.dto.reuploadkey;
+
+import java.util.Arrays;
+
+public enum ReuploadKeyStatus {
+
+    COMPLETED("N/A"), FAILED("N/A");
+
+    private String message;
+
+    ReuploadKeyStatus(String message) {
+        this.message = message;
+    }
+
+    public ReuploadKeyStatus withErrorMessage(String message) {
+        this.message = message;
+        return this;
+    }
+
+    public String message() {
+        return message;
+    }
+
+    public static ReuploadKeyStatus fromValue(String value) {
+        return Arrays.stream(values())
+                .filter(v -> v.name().equalsIgnoreCase(value))
+                .findAny()
+                .orElseThrow(() ->
+                        new IllegalArgumentException("Wrong value for ReuploadKeyStatus: " + value));
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/reuploadkey/ReuploadKeyStatusDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/reuploadkey/ReuploadKeyStatusDTO.java
new file mode 100644
index 0000000..481d185
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/reuploadkey/ReuploadKeyStatusDTO.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab.dto.reuploadkey;
+
+import com.epam.datalab.dto.StatusBaseDTO;
+import com.google.common.base.MoreObjects;
+import lombok.Getter;
+
+@Getter
+public class ReuploadKeyStatusDTO extends StatusBaseDTO<ReuploadKeyStatusDTO> {
+
+    private ReuploadKeyCallbackDTO reuploadKeyCallbackDTO;
+    private ReuploadKeyStatus reuploadKeyStatus;
+
+
+    public ReuploadKeyStatusDTO withReuploadKeyCallbackDto(ReuploadKeyCallbackDTO reuploadKeyCallbackDTO) {
+        this.reuploadKeyCallbackDTO = reuploadKeyCallbackDTO;
+        return this;
+    }
+
+    public ReuploadKeyStatusDTO withReuploadKeyStatus(ReuploadKeyStatus status) {
+        this.reuploadKeyStatus = status;
+        return this;
+    }
+
+    @Override
+    public MoreObjects.ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("reuploadKeyStatus", reuploadKeyStatus)
+                .add("reuploadKeyCallbackDTO", reuploadKeyCallbackDTO);
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/status/EnvResource.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/status/EnvResource.java
new file mode 100644
index 0000000..f18ebe9
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/status/EnvResource.java
@@ -0,0 +1,161 @@
+/*
+ * 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.datalab.dto.status;
+
+import com.epam.datalab.model.ResourceType;
+import com.epam.datalab.util.mongo.IsoLocalDateTimeDeSerializer;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * Describe the resource (host, cluster, storage) for check status in Cloud.
+ */
+@NoArgsConstructor
+public class EnvResource {
+    @JsonProperty
+    private String id;
+    @JsonProperty
+    private String status;
+    @JsonProperty
+    private String name;
+    @JsonProperty
+    private ResourceType resourceType;
+    @JsonProperty("project_name")
+    private String project;
+    @JsonProperty("endpoint_name")
+    private String endpoint;
+    @JsonDeserialize(using = IsoLocalDateTimeDeSerializer.class)
+    @JsonProperty
+    private LocalDateTime lastActivity;
+
+    public EnvResource(String id, String name, ResourceType resourceType, String project, String endpoint) {
+        this.id = id;
+        this.name = name;
+        this.resourceType = resourceType;
+        this.project = project;
+        this.endpoint = endpoint;
+    }
+
+    /**
+     * Return the id of resource. instanceId for host, clusterId for cluster, path for storage.
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Set the id of resource. instanceId for host, clusterId for cluster, path for storage.
+     */
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    /**
+     * Set the id of resource. instanceId for host, clusterId for cluster, path for storage.
+     */
+    public EnvResource withId(String id) {
+        setId(id);
+        return this;
+    }
+
+    /**
+     * Return the status of resource.
+     */
+    public String getStatus() {
+        return status;
+    }
+
+    /**
+     * Set the status of resource.
+     */
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    /**
+     * Set the status of resource.
+     */
+    public EnvResource withStatus(String status) {
+        setStatus(status);
+        return this;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public ResourceType getResourceType() {
+        return resourceType;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public EnvResource withName(String name) {
+        setName(name);
+        return this;
+    }
+
+    public EnvResource withResourceType(ResourceType resourceType) {
+        setResourceType(resourceType);
+        return this;
+    }
+
+    public void setResourceType(ResourceType resourceType) {
+        this.resourceType = resourceType;
+    }
+
+    public LocalDateTime getLastActivity() {
+        return lastActivity;
+    }
+
+    public void setLastActivity(LocalDateTime lastActivity) {
+        this.lastActivity = lastActivity;
+    }
+
+    public EnvResource withLastActivity(LocalDateTime lastActivity) {
+        setLastActivity(lastActivity);
+        return this;
+    }
+
+    public String getEndpoint() {
+        return endpoint;
+    }
+
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("id", id)
+                .add("status", status)
+                .add("name", name)
+                .add("resourceType", resourceType)
+                .add("lastActivity", lastActivity);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/status/EnvResourceList.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/status/EnvResourceList.java
new file mode 100644
index 0000000..0a3d292
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/status/EnvResourceList.java
@@ -0,0 +1,91 @@
+/*
+ * 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.datalab.dto.status;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.List;
+
+/**
+ * Describe the lists of resources (host, cluster, storage) for check status in Cloud.
+ */
+public class EnvResourceList {
+    @JsonProperty("host")
+    private List<EnvResource> hostList;
+    @JsonProperty("cluster")
+    private List<EnvResource> clusterList;
+
+    /**
+     * Return the list of hosts.
+     */
+    public List<EnvResource> getHostList() {
+        return hostList;
+    }
+
+    /**
+     * Set the list of hosts.
+     */
+    public void setHostList(List<EnvResource> hostList) {
+        this.hostList = hostList;
+    }
+
+    /**
+     * Set the list of hosts.
+     */
+    public EnvResourceList withHostList(List<EnvResource> hostList) {
+        setHostList(hostList);
+        return this;
+    }
+
+    /**
+     * Return the list of clusters.
+     */
+    public List<EnvResource> getClusterList() {
+        return clusterList;
+    }
+
+    /**
+     * Set the list of clusters.
+     */
+    public void setClusterList(List<EnvResource> clusterList) {
+        this.clusterList = clusterList;
+    }
+
+    /**
+     * Set the list of clusters.
+     */
+    public EnvResourceList withClusterList(List<EnvResource> clusterList) {
+        setClusterList(clusterList);
+        return this;
+    }
+
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("host", hostList)
+                .add("cluster", clusterList);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/status/EnvStatusDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/status/EnvStatusDTO.java
new file mode 100644
index 0000000..5fee995
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/status/EnvStatusDTO.java
@@ -0,0 +1,65 @@
+/*
+ * 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.datalab.dto.status;
+
+import com.epam.datalab.dto.StatusBaseDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+/**
+ * Describe the lists of resources (host, cluster, storage) for check status in Cloud.
+ */
+public class EnvStatusDTO extends StatusBaseDTO<EnvStatusDTO> {
+    @JsonProperty("edge_list_resources")
+    private EnvResourceList resourceList;
+
+    /**
+     * Return the list of resources (hosts, clusters, storages).
+     */
+    public EnvResourceList getResourceList() {
+        return resourceList;
+    }
+
+    /**
+     * Set the list of resources (hosts, clusters, storages).
+     */
+    public void setResourceList(EnvResourceList resourceList) {
+        this.resourceList = resourceList;
+    }
+
+    /**
+     * Set the list of resources (hosts, clusters, storages).
+     */
+    public EnvStatusDTO withResourceList(EnvResourceList resourceList) {
+        setResourceList(resourceList);
+        return this;
+    }
+
+    @Override
+    public ToStringHelper toStringHelper(Object self) {
+        return super.toStringHelper(self)
+                .add("resourceList", resourceList);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/ResourceData.java b/services/datalab-model/src/main/java/com/epam/datalab/model/ResourceData.java
new file mode 100644
index 0000000..e4a4245
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/ResourceData.java
@@ -0,0 +1,60 @@
+/*
+ * 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.datalab.model;
+
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+@EqualsAndHashCode
+public class ResourceData {
+    private ResourceType resourceType;
+    private String resourceId;
+    private String exploratoryName;
+    private String computationalName;
+
+    public static ResourceData edgeResource(String resourceId) {
+        return new ResourceData(ResourceType.EDGE, resourceId, null, null);
+    }
+
+    public static ResourceData exploratoryResource(String resourceId, String exploratoryName) {
+        return new ResourceData(ResourceType.EXPLORATORY, resourceId, exploratoryName, null);
+    }
+
+    public static ResourceData computationalResource(String resourceId, String exploratoryName,
+                                                     String computationalName) {
+        return new ResourceData(ResourceType.COMPUTATIONAL, resourceId, exploratoryName, computationalName);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        if (resourceType == ResourceType.EDGE) {
+            return sb.append(resourceType.toString()).toString();
+        } else if (resourceType == ResourceType.EXPLORATORY) {
+            return sb.append(resourceType.toString()).append(" ").append(exploratoryName).toString();
+        } else if (resourceType == ResourceType.COMPUTATIONAL) {
+            return sb.append(resourceType.toString()).append(" ").append(computationalName)
+                    .append(" affiliated with exploratory ").append(exploratoryName).toString();
+        } else return "";
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/ResourceEnum.java b/services/datalab-model/src/main/java/com/epam/datalab/model/ResourceEnum.java
new file mode 100644
index 0000000..0cf7832
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/ResourceEnum.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.model;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+public enum ResourceEnum {
+    EDGE_NODE("edge node"),
+    NOTEBOOK("notebook");
+
+    private String name;
+
+    ResourceEnum(String name) {
+        this.name = name;
+    }
+
+    @JsonValue
+    @Override
+    public String toString() {
+        return name;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/ResourceType.java b/services/datalab-model/src/main/java/com/epam/datalab/model/ResourceType.java
new file mode 100644
index 0000000..2997144
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/ResourceType.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab.model;
+
+public enum ResourceType {
+    COMPUTATIONAL("computational_resource"),
+    EDGE("edge_node"),
+    EXPLORATORY("exploratory");
+
+    private String name;
+
+    ResourceType(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/StringList.java b/services/datalab-model/src/main/java/com/epam/datalab/model/StringList.java
new file mode 100644
index 0000000..a62d9e1
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/StringList.java
@@ -0,0 +1,47 @@
+/*
+ * 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.datalab.model;
+
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.WebApplicationException;
+import java.util.ArrayList;
+
+@Slf4j
+public class StringList extends ArrayList<String> {
+    public StringList(String s) {
+        super();
+
+        for (String v : s.split(",")) {
+            try {
+                add(v.trim());
+            } catch (Exception e) {
+                log.error("Something went wrong. Reason {}", e.getMessage(), e);
+                throw new WebApplicationException(400);
+            }
+        }
+        if (isEmpty())
+            throw new WebApplicationException(400);
+    }
+
+    public static String valueOf(String s) {
+        return s;
+    }
+}
\ No newline at end of file
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/aws/BillingResourceType.java b/services/datalab-model/src/main/java/com/epam/datalab/model/aws/BillingResourceType.java
new file mode 100644
index 0000000..261fe5e
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/aws/BillingResourceType.java
@@ -0,0 +1,80 @@
+/*
+ * 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.datalab.model.aws;
+
+/**
+ * Billing resource types.
+ */
+public enum BillingResourceType {
+    COMPUTER,
+    CLUSTER,
+    STORAGE,
+    STORAGE_EBS,
+    STORAGE_BUCKET,
+    IP_ADDRESS,
+    OTHER;
+
+    public static BillingResourceType of(String string) {
+        if (string != null) {
+            for (BillingResourceType value : BillingResourceType.values()) {
+                if (string.equalsIgnoreCase(value.toString())) {
+                    return value;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Return the category of resource.
+     *
+     * @param resourceType the type of resource.
+     */
+    public static String category(BillingResourceType resourceType) {
+        switch (resourceType) {
+            case COMPUTER:
+                return "EC2";
+            case CLUSTER:
+                return "Compute";
+            case STORAGE:
+                return "Storage";
+            case STORAGE_EBS:
+                return "EBS";
+            case STORAGE_BUCKET:
+                return "S3";
+            case IP_ADDRESS:
+                return "Static";
+            default:
+                return "Other";
+        }
+    }
+
+    /**
+     * Return the category of resource.
+     */
+    public String category() {
+        return category(this);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString().toUpperCase();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/aws/ReportLine.java b/services/datalab-model/src/main/java/com/epam/datalab/model/aws/ReportLine.java
new file mode 100644
index 0000000..cb41a5a
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/aws/ReportLine.java
@@ -0,0 +1,233 @@
+/*
+ * 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.datalab.model.aws;
+
+import com.epam.datalab.exceptions.ParseException;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.LinkedHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * The line of billing report.
+ */
+public class ReportLine {
+    /**
+     * Patterns to calculate the type of resource in report line.
+     */
+    private static final Pattern pInstancceId = Pattern.compile("^i-[a-z0-9]{17}$");
+    private static final Pattern pVolumeId = Pattern.compile("^vol-[a-z0-9]{17}$");
+    private static final Pattern pIpAddress = Pattern.compile("^[1-9][0-9]{0,2}\\.[1-9][0-9]{0,2}\\.[1-9][0-9]{0,2}\\.[1-9][0-9]{0,2}$");
+    private static final Pattern pClusterId = Pattern.compile("j-[A-Z0-9]{12,13}$");
+
+    public static final String FIELD_DATALAB_ID = "datalab_id";
+    public static final String FIELD_USER_ID = "user";
+    public static final String FIELD_USAGE_DATE = "usage_date";
+    public static final String FIELD_PRODUCT = "product";
+    public static final String FIELD_USAGE_TYPE = "usage_type";
+    public static final String FIELD_USAGE = "usage";
+    public static final String FIELD_COST = "cost";
+    public static final String FIELD_CURRENCY_CODE = "currency_code";
+    public static final String FIELD_RESOURCE_TYPE = "resource_type";
+    public static final String FIELD_RESOURCE_ID = "resource_id";
+    public static final String FIELD_TAGS = "tags";
+
+    @JsonProperty
+    private String datalabId;
+
+    @JsonProperty
+    private String user;
+
+    @JsonProperty
+    private String usageDate;
+
+    @JsonProperty
+    private String usageIntervalEnd;
+
+    @JsonProperty
+    private String product;
+
+    @JsonProperty
+    private String usageType;
+
+    @JsonProperty
+    private double usage;
+
+    @JsonProperty
+    private double cost;
+
+    @JsonProperty
+    private String currencyCode;
+
+    @JsonProperty
+    private BillingResourceType resourceType;
+
+    @JsonProperty
+    private String resourceId;
+
+    @JsonProperty
+    private LinkedHashMap<String, String> tags;
+
+
+    public String getDatalabId() {
+        return datalabId;
+    }
+
+    public void setDatalabId(String datalabId) {
+        this.datalabId = datalabId;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public String getUsageDate() {
+        return usageDate;
+    }
+
+    public void setUsageDate(String usageDate) {
+        this.usageDate = usageDate;
+    }
+
+    public String getProduct() {
+        return product;
+    }
+
+    public void setProduct(String product) {
+        this.product = product;
+    }
+
+    public String getUsageType() {
+        return usageType;
+    }
+
+    public void setUsageType(String usageType) {
+        this.usageType = usageType;
+    }
+
+    public double getUsage() {
+        return usage;
+    }
+
+    public void setUsage(double usage) {
+        this.usage = usage;
+    }
+
+    public double getCost() {
+        return cost;
+    }
+
+    public void setCost(double cost) {
+        this.cost = cost;
+    }
+
+    public String getCurrencyCode() {
+        return currencyCode;
+    }
+
+    public void setCurrencyCode(String currencyCode) {
+        this.currencyCode = currencyCode;
+    }
+
+    public String getResourceId() {
+        return resourceId;
+    }
+
+    public BillingResourceType getResourceType() {
+        return resourceType;
+    }
+
+    public LinkedHashMap<String, String> getTags() {
+        return tags;
+    }
+
+    public void setTags(LinkedHashMap<String, String> tags) {
+        this.tags = tags;
+    }
+
+    /**
+     * Calculate and set the type of resource and resource id.
+     *
+     * @throws ParseException
+     */
+    public void setResourceTypeId(String resourceTypeId) throws ParseException {
+        if (product == null) {
+            throw new ParseException("Property product is not set");
+        }
+
+        if ("Amazon Elastic MapReduce".equals(product) ||
+                "Amazon Simple Queue Service".equals(product)) {
+            resourceType = BillingResourceType.CLUSTER;
+            Matcher m = pClusterId.matcher(resourceTypeId);
+            resourceId = (m.find() ? m.group() : null);
+        } else {
+            if ("Amazon Elastic Compute Cloud".equals(product)) {
+                if (pInstancceId.matcher(resourceTypeId).find()) {
+                    resourceType = BillingResourceType.COMPUTER;
+                } else if (pVolumeId.matcher(resourceTypeId).find()) {
+                    resourceType = BillingResourceType.STORAGE_EBS;
+                } else if (pIpAddress.matcher(resourceTypeId).find()) {
+                    resourceType = BillingResourceType.IP_ADDRESS;
+                } else {
+                    resourceType = BillingResourceType.COMPUTER;
+                }
+            } else if ("Amazon Simple Storage Service".equals(product)) {
+                resourceType = BillingResourceType.STORAGE_BUCKET;
+            } else {
+                resourceType = BillingResourceType.OTHER;
+            }
+            resourceId = resourceTypeId;
+        }
+    }
+
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @param self the object to generate the string for (typically this), used only for its class name.
+     */
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add(FIELD_DATALAB_ID, datalabId)
+                .add(FIELD_USER_ID, user)
+                .add(FIELD_USAGE_DATE, usageDate)
+                .add(FIELD_PRODUCT, product)
+                .add(FIELD_USAGE_TYPE, usageType)
+                .add(FIELD_USAGE, usage)
+                .add(FIELD_COST, cost)
+                .add(FIELD_CURRENCY_CODE, currencyCode)
+                .add(FIELD_RESOURCE_TYPE, resourceType)
+                .add(FIELD_RESOURCE_ID, resourceId)
+                .add(FIELD_TAGS, tags);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .toString();
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/azure/AzureAuthFile.java b/services/datalab-model/src/main/java/com/epam/datalab/model/azure/AzureAuthFile.java
new file mode 100644
index 0000000..3503044
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/azure/AzureAuthFile.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.datalab.model.azure;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.ToString;
+
+@Getter
+@ToString(exclude = {"clientSecret"})
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class AzureAuthFile {
+    @JsonProperty
+    private String clientId;
+    @JsonProperty
+    private String clientSecret;
+    @JsonProperty
+    private String tenantId;
+    @JsonProperty
+    private String subscriptionId;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/exploratory/Exploratory.java b/services/datalab-model/src/main/java/com/epam/datalab/model/exploratory/Exploratory.java
new file mode 100644
index 0000000..176e6a9
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/exploratory/Exploratory.java
@@ -0,0 +1,41 @@
+/*
+ * 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.datalab.model.exploratory;
+
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Builder
+public class Exploratory {
+    private final String name;
+    private final String dockerImage;
+    private final String version;
+    private final String templateName;
+    private final String shape;
+    private final String imageName;
+    private final String endpoint;
+    private final String project;
+    private final String exploratoryTag;
+    private final List<ClusterConfig> clusterConfig;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/exploratory/Image.java b/services/datalab-model/src/main/java/com/epam/datalab/model/exploratory/Image.java
new file mode 100644
index 0000000..c8d3b2c
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/exploratory/Image.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.model.exploratory;
+
+import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.epam.datalab.model.library.Library;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+@Builder
+public class Image {
+    private final String name;
+    private final String description;
+    private final ImageStatus status;
+    private final String exploratoryId;
+    private final String project;
+    private final String endpoint;
+    private final String user;
+    private final String fullName;
+    private final String externalName;
+    private final String application;
+    private final String dockerImage;
+    private final List<Library> libraries;
+    private final Map<String, List<Library>> computationalLibraries;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/library/Library.java b/services/datalab-model/src/main/java/com/epam/datalab/model/library/Library.java
new file mode 100644
index 0000000..28ec026
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/library/Library.java
@@ -0,0 +1,55 @@
+/*
+ * 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.datalab.model.library;
+
+import com.epam.datalab.dto.exploratory.LibStatus;
+import com.epam.datalab.model.ResourceType;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Library {
+    private final String group;
+    private final String name;
+    private final String version;
+    private final LibStatus status;
+    @JsonProperty("error_message")
+    private final String errorMessage;
+    @JsonProperty("available_versions")
+    private List<String> availableVersions;
+    @JsonProperty("add_pkgs")
+    private List<String> addedPackages;
+    private String resourceName;
+    private ResourceType type;
+
+    public Library withType(ResourceType type) {
+        setType(type);
+        return this;
+    }
+
+    public Library withResourceName(String name) {
+        setResourceName(name);
+        return this;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/scheduler/SchedulerJobData.java b/services/datalab-model/src/main/java/com/epam/datalab/model/scheduler/SchedulerJobData.java
new file mode 100644
index 0000000..47aea0e
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/scheduler/SchedulerJobData.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.model.scheduler;
+
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class SchedulerJobData {
+
+    @JsonProperty
+    private final String user;
+
+    @JsonProperty("exploratory_name")
+    private final String exploratoryName;
+
+    @JsonProperty("computational_name")
+    private final String computationalName;
+
+    @JsonProperty
+    private final String project;
+
+    @JsonProperty("scheduler_data")
+    private final SchedulerJobDTO jobDTO;
+}
+
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/systeminfo/DiskInfo.java b/services/datalab-model/src/main/java/com/epam/datalab/model/systeminfo/DiskInfo.java
new file mode 100644
index 0000000..e354269
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/systeminfo/DiskInfo.java
@@ -0,0 +1,36 @@
+/*
+ * 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.datalab.model.systeminfo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class DiskInfo {
+
+    @JsonProperty
+    private String serialNumber;
+    @JsonProperty
+    private long usedByteSpace;
+    @JsonProperty
+    private long totalByteSpace;
+
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/systeminfo/MemoryInfo.java b/services/datalab-model/src/main/java/com/epam/datalab/model/systeminfo/MemoryInfo.java
new file mode 100644
index 0000000..7cdb73d
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/systeminfo/MemoryInfo.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.datalab.model.systeminfo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class MemoryInfo {
+
+    @JsonProperty
+    private long availableMemory;
+    @JsonProperty
+    private long totalMemory;
+
+    private long swapTotal;
+    private long swapUsed;
+    private long pagesPageIn;
+    private long pagesPageOut;
+
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/systeminfo/OsInfo.java b/services/datalab-model/src/main/java/com/epam/datalab/model/systeminfo/OsInfo.java
new file mode 100644
index 0000000..83181a7
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/systeminfo/OsInfo.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.model.systeminfo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class OsInfo {
+
+    @JsonProperty
+    private String manufacturer;
+    @JsonProperty
+    private String family;
+    @JsonProperty
+    private String version;
+    @JsonProperty
+    private String buildNumber;
+
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/systeminfo/ProcessorInfo.java b/services/datalab-model/src/main/java/com/epam/datalab/model/systeminfo/ProcessorInfo.java
new file mode 100644
index 0000000..771626f
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/systeminfo/ProcessorInfo.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.model.systeminfo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class ProcessorInfo {
+
+    private String model;
+    private String family;
+
+    @JsonProperty
+    private String name;
+
+    private String id;
+    private String vendor;
+    private int logicalCoreCount;
+    private int physicalCoreCount;
+    private boolean isCpu64Bit;
+
+    @JsonProperty
+    private double currentSystemLoad;
+    @JsonProperty
+    private double systemLoadAverage;
+
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/util/CloudSettingsDeserializer.java b/services/datalab-model/src/main/java/com/epam/datalab/util/CloudSettingsDeserializer.java
new file mode 100644
index 0000000..b031163
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/util/CloudSettingsDeserializer.java
@@ -0,0 +1,88 @@
+/*
+ * 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.datalab.util;
+
+import com.epam.datalab.dto.aws.AwsCloudSettings;
+import com.epam.datalab.dto.azure.AzureCloudSettings;
+import com.epam.datalab.dto.base.CloudSettings;
+import com.epam.datalab.dto.gcp.GcpCloudSettings;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+@Slf4j
+public class CloudSettingsDeserializer extends JsonDeserializer<CloudSettings> {
+    @Override
+    public CloudSettings deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+        JsonNode jsonNode = p.readValueAsTree();
+
+        Map<String, String> mapJson = new HashMap<>();
+        for (Iterator<String> it = jsonNode.fieldNames(); it.hasNext(); ) {
+            String s = it.next();
+            mapJson.put(s, jsonNode.get(s).textValue());
+        }
+
+        try {
+            return createFromMap(detectCloudSettings(mapJson), mapJson);
+        } catch (IllegalAccessException e) {
+            log.error("Cannot deserialize object due to {}", e.getMessage(), e);
+            throw new IllegalArgumentException("Cannot deserialize cloud settings " + mapJson);
+        }
+    }
+
+    private CloudSettings detectCloudSettings(Map<String, String> properties) {
+        for (Map.Entry<String, String> entry : properties.entrySet()) {
+            if (entry.getKey().startsWith("aws")) {
+                return new AwsCloudSettings();
+            } else if (entry.getKey().startsWith("azure")) {
+                return new AzureCloudSettings();
+            } else if (entry.getKey().startsWith("gcp")) {
+                return new GcpCloudSettings();
+            }
+        }
+        throw new IllegalArgumentException("Unknown properties " + properties);
+    }
+
+    private <T extends CloudSettings> T createFromMap(T settings, Map<String, String> map) throws
+            IllegalAccessException {
+        for (Field field : settings.getClass().getDeclaredFields()) {
+            if (field.getAnnotation(JsonProperty.class) != null) {
+                String value = map.get(field.getAnnotation(JsonProperty.class).value());
+                if (value != null) {
+                    field.setAccessible(true);
+                    field.set(settings, value);
+
+                }
+            }
+        }
+
+        return settings;
+    }
+
+}
\ No newline at end of file
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/util/JsonGenerator.java b/services/datalab-model/src/main/java/com/epam/datalab/util/JsonGenerator.java
new file mode 100644
index 0000000..c558b77
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/util/JsonGenerator.java
@@ -0,0 +1,54 @@
+/*
+ * 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.datalab.util;
+
+import com.epam.datalab.dto.ResourceBaseDTO;
+import com.epam.datalab.dto.base.CloudSettings;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public final class JsonGenerator {
+    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
+            .setSerializationInclusion(JsonInclude.Include.NON_NULL)
+            .addMixIn(ResourceBaseDTO.class, CloudSettingsUnwrapping.class);
+
+    private JsonGenerator() {
+    }
+
+    public static String generateJson(ResourceBaseDTO<?> resourceBaseDTO) throws JsonProcessingException {
+        return generateJson(resourceBaseDTO, false);
+    }
+
+    private static String generateJson(ResourceBaseDTO<?> resourceBaseDTO, boolean pretty) throws
+            JsonProcessingException {
+        if (pretty) {
+            return OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(resourceBaseDTO);
+        } else {
+            return OBJECT_MAPPER.writeValueAsString(resourceBaseDTO);
+        }
+    }
+
+    private abstract static class CloudSettingsUnwrapping {
+        @JsonUnwrapped
+        private CloudSettings cloudSettings;
+    }
+}
diff --git a/services/datalab-model/src/test/java/com/epam/datalab/dto/status/EnvResourceDTOTest.java b/services/datalab-model/src/test/java/com/epam/datalab/dto/status/EnvResourceDTOTest.java
new file mode 100644
index 0000000..5d76825
--- /dev/null
+++ b/services/datalab-model/src/test/java/com/epam/datalab/dto/status/EnvResourceDTOTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.datalab.dto.status;
+
+import com.epam.datalab.dto.UserEnvironmentResources;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class EnvResourceDTOTest {
+
+    private static String getJsonString(Object object) throws JsonProcessingException {
+        ObjectMapper objectMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
+        return objectMapper.writeValueAsString(object);
+    }
+
+    private static <T> T getJsonObject(String string, Class<T> objectType) throws IOException {
+        ObjectMapper objectMapper = new ObjectMapper();
+        return objectMapper.readValue(string, objectType);
+    }
+
+    @Test
+    public void serde() throws IOException {
+        List<EnvResource> hosts1 = new ArrayList<EnvResource>();
+        hosts1.add(new EnvResource().withId("1"));
+        hosts1.add(new EnvResource().withId("2"));
+        hosts1.add(new EnvResource().withId("3").withStatus("state3"));
+        assertEquals(hosts1.get(0).getId(), "1");
+        assertEquals(hosts1.get(2).getStatus(), "state3");
+
+        List<EnvResource> clusters1 = new ArrayList<EnvResource>();
+        clusters1.add(new EnvResource().withId("10"));
+        clusters1.add(new EnvResource().withId("11"));
+        assertEquals(clusters1.get(0).getId(), "10");
+
+        EnvResourceList r1 = new EnvResourceList()
+                .withHostList(hosts1).withClusterList(clusters1);
+        assertEquals(r1.getHostList().get(1).getId(), "2");
+        assertEquals(r1.getHostList().get(2).getId(), "3");
+        assertEquals(r1.getClusterList().get(1).getId(), "11");
+
+        UserEnvironmentResources rs1 = new UserEnvironmentResources()
+                .withResourceList(r1);
+        assertEquals(rs1.getResourceList().getHostList().get(0).getId(), "1");
+        assertEquals(rs1.getResourceList().getClusterList().get(0).getId(), "10");
+
+        String json1 = getJsonString(rs1);
+
+        UserEnvironmentResources rs2 = getJsonObject(json1, UserEnvironmentResources.class);
+        String json2 = getJsonString(rs2);
+        assertEquals(rs1.getResourceList().getHostList().size(), rs2.getResourceList().getHostList().size());
+        assertEquals(rs1.getResourceList().getClusterList().size(), rs2.getResourceList().getClusterList().size());
+
+        assertEquals("Json SerDe error", json1, json2);
+    }
+}
diff --git a/services/datalab-model/src/test/java/com/epam/datalab/dto/status/EnvStatusDTOTest.java b/services/datalab-model/src/test/java/com/epam/datalab/dto/status/EnvStatusDTOTest.java
new file mode 100644
index 0000000..fbdb3f7
--- /dev/null
+++ b/services/datalab-model/src/test/java/com/epam/datalab/dto/status/EnvStatusDTOTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.datalab.dto.status;
+
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class EnvStatusDTOTest {
+
+    private static String getJsonString(Object object) throws JsonProcessingException {
+        ObjectMapper objectMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
+        return objectMapper.writeValueAsString(object);
+    }
+
+    private static <T> T getJsonObject(String string, Class<T> objectType) throws IOException {
+        ObjectMapper objectMapper = new ObjectMapper();
+        return objectMapper.readValue(string, objectType);
+    }
+
+    @Test
+    public void serde() throws IOException {
+        List<EnvResource> hosts1 = new ArrayList<>();
+        hosts1.add(new EnvResource().withId("1"));
+        hosts1.add(new EnvResource().withId("2"));
+        hosts1.add(new EnvResource().withId("3").withStatus("state3"));
+        assertEquals(hosts1.get(0).getId(), "1");
+        assertEquals(hosts1.get(2).getStatus(), "state3");
+
+        List<EnvResource> clusters1 = new ArrayList<EnvResource>();
+        clusters1.add(new EnvResource().withId("10"));
+        clusters1.add(new EnvResource().withId("11"));
+        assertEquals(clusters1.get(0).getId(), "10");
+
+        EnvResourceList r1 = new EnvResourceList()
+                .withHostList(hosts1).withClusterList(clusters1);
+        assertEquals(r1.getHostList().get(1).getId(), "2");
+        assertEquals(r1.getHostList().get(2).getId(), "3");
+        assertEquals(r1.getClusterList().get(1).getId(), "11");
+
+        EnvStatusDTO rs1 = new EnvStatusDTO()
+                .withUser("user1")
+                .withUptime(new Date())
+                .withStatus(UserInstanceStatus.CREATED)
+                .withErrorMessage("errorMessage1")
+                .withResourceList(r1);
+        assertEquals(rs1.getResourceList().getHostList().get(0).getId(), "1");
+        assertEquals(rs1.getResourceList().getClusterList().get(0).getId(), "10");
+
+        String json1 = getJsonString(rs1);
+
+        EnvStatusDTO rs2 = getJsonObject(json1, EnvStatusDTO.class);
+        String json2 = getJsonString(rs2);
+        assertEquals(rs1.getUser(), rs2.getUser());
+        assertEquals(rs1.getUptime(), rs2.getUptime());
+        assertEquals(rs1.getStatus(), rs2.getStatus());
+        assertEquals(rs1.getErrorMessage(), rs2.getErrorMessage());
+        assertEquals(rs1.getResourceList().getHostList().size(), rs2.getResourceList().getHostList().size());
+        assertEquals(rs1.getResourceList().getClusterList().size(), rs2.getResourceList().getClusterList().size());
+
+        assertEquals("Json SerDe error", json1, json2);
+    }
+}
diff --git a/services/datalab-model/src/test/java/com/epam/datalab/util/JsonGeneratorTest.java b/services/datalab-model/src/test/java/com/epam/datalab/util/JsonGeneratorTest.java
new file mode 100644
index 0000000..a87b0ab
--- /dev/null
+++ b/services/datalab-model/src/test/java/com/epam/datalab/util/JsonGeneratorTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab.util;
+
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyDTO;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JsonGeneratorTest {
+
+    @Test
+    public void generateJsonTest() throws JsonProcessingException {
+        ReuploadKeyDTO dto = new ReuploadKeyDTO();
+        dto.withContent("someContent").withId("someId").withEdgeUserName("edgeUserName").withServiceBaseName("SBN");
+        String actual = JsonGenerator.generateJson(dto);
+        String expected = "{\"@class\":\"com.epam.datalab.dto.reuploadkey.ReuploadKeyDTO\",\"content\":\"someContent\"," +
+                "\"id\":\"someId\",\"edge_user_name\":\"edgeUserName\",\"conf_service_base_name\":\"SBN\"}";
+        Assert.assertEquals(expected, actual);
+    }
+}
diff --git a/services/datalab-mongo-migration/pom.xml b/services/datalab-mongo-migration/pom.xml
new file mode 100644
index 0000000..56dcb90
--- /dev/null
+++ b/services/datalab-mongo-migration/pom.xml
@@ -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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.epam.datalab</groupId>
+        <artifactId>datalab</artifactId>
+        <version>1.0</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>datalab-mongo-migration</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.github.mongobee</groupId>
+            <artifactId>mongobee</artifactId>
+            <version>0.13</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/services/datalab-mongo-migration/src/main/java/com/epam/datalab/migration/DbMigration.java b/services/datalab-mongo-migration/src/main/java/com/epam/datalab/migration/DbMigration.java
new file mode 100644
index 0000000..9cf230d
--- /dev/null
+++ b/services/datalab-mongo-migration/src/main/java/com/epam/datalab/migration/DbMigration.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.datalab.migration;
+
+@FunctionalInterface
+public interface DbMigration {
+
+    void migrate();
+}
diff --git a/services/datalab-mongo-migration/src/main/java/com/epam/datalab/migration/exception/DatalabDbMigrationException.java b/services/datalab-mongo-migration/src/main/java/com/epam/datalab/migration/exception/DatalabDbMigrationException.java
new file mode 100644
index 0000000..376aee5
--- /dev/null
+++ b/services/datalab-mongo-migration/src/main/java/com/epam/datalab/migration/exception/DatalabDbMigrationException.java
@@ -0,0 +1,27 @@
+/*
+ * 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.datalab.migration.exception;
+
+public class DatalabDbMigrationException extends RuntimeException {
+
+	public DatalabDbMigrationException(String message, Throwable cause) {
+		super(message, cause);
+	}
+}
diff --git a/services/datalab-mongo-migration/src/main/java/com/epam/datalab/migration/mongo/DatalabMongoMigration.java b/services/datalab-mongo-migration/src/main/java/com/epam/datalab/migration/mongo/DatalabMongoMigration.java
new file mode 100644
index 0000000..7f4b49a
--- /dev/null
+++ b/services/datalab-mongo-migration/src/main/java/com/epam/datalab/migration/mongo/DatalabMongoMigration.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab.migration.mongo;
+
+import com.epam.datalab.migration.DbMigration;
+import com.epam.datalab.migration.exception.DatalabDbMigrationException;
+import com.epam.datalab.migration.mongo.changelog.DatalabChangeLog;
+import com.github.mongobee.Mongobee;
+import com.github.mongobee.exception.MongobeeException;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class DatalabMongoMigration implements DbMigration {
+    private static final String MONGODB_URI_FORMAT = "mongodb://%s:%s@%s:%d/%s";
+    private final Mongobee runner;
+
+    public DatalabMongoMigration(String host, int port, String user, String password, String db) {
+        runner = new Mongobee(String.format(MONGODB_URI_FORMAT, user, password, host, port, db));
+        runner.setDbName(db);
+        runner.setChangeLogsScanPackage(DatalabChangeLog.class.getPackage().getName());
+    }
+
+    public void migrate() {
+        try {
+            runner.execute();
+        } catch (MongobeeException e) {
+            log.error("Mongo db migration failed: {}", e.getMessage());
+            throw new DatalabDbMigrationException("Mongo db migration failed", e);
+        }
+    }
+}
diff --git a/services/datalab-mongo-migration/src/main/java/com/epam/datalab/migration/mongo/changelog/DatalabChangeLog.java b/services/datalab-mongo-migration/src/main/java/com/epam/datalab/migration/mongo/changelog/DatalabChangeLog.java
new file mode 100644
index 0000000..facc337
--- /dev/null
+++ b/services/datalab-mongo-migration/src/main/java/com/epam/datalab/migration/mongo/changelog/DatalabChangeLog.java
@@ -0,0 +1,66 @@
+/*
+ * 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.datalab.migration.mongo.changelog;
+
+import com.github.mongobee.changeset.ChangeLog;
+import com.github.mongobee.changeset.ChangeSet;
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import com.mongodb.DBObject;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.StreamSupport;
+
+@ChangeLog
+@Slf4j
+public class DatalabChangeLog {
+
+    public static final String ID = "_id";
+
+    @ChangeSet(order = "001", id = "001", author = "bhliva")
+    public void migrateSchedulerFields(DB db) {
+        log.info("Replacing field days_repeat with start_days_repeat and stop_days_repeat");
+        final DBCollection userInstances = db.getCollection("userInstances");
+
+        StreamSupport.stream(userInstances.find().spliterator(), false)
+                .forEach(dbObject -> updateSchedulerFieldsForExploratory(userInstances, dbObject));
+        log.info("Replacing scheduler field days_repeat finished successfully");
+    }
+
+    @SuppressWarnings("unchecked")
+    private void updateSchedulerFieldsForExploratory(DBCollection userInstances, DBObject dbObject) {
+        updateSchedulerFields(dbObject);
+        Optional.ofNullable(dbObject.get("computational_resources")).map(cr -> (List<DBObject>) cr)
+                .ifPresent(computationalResources -> computationalResources.forEach(this::updateSchedulerFields));
+        userInstances.update(new BasicDBObject(ID, dbObject.get(ID)), dbObject);
+    }
+
+    private void updateSchedulerFields(DBObject dbObject) {
+        final Object schedulerData = dbObject.get("scheduler_data");
+        if (schedulerData != null) {
+            final Object daysRepeat = ((DBObject) schedulerData).removeField("days_repeat");
+            ((DBObject) schedulerData).put("start_days_repeat", daysRepeat);
+            ((DBObject) schedulerData).put("stop_days_repeat", daysRepeat);
+        }
+    }
+}
diff --git a/services/datalab-utils/pom.xml b/services/datalab-utils/pom.xml
new file mode 100644
index 0000000..265ffb7
--- /dev/null
+++ b/services/datalab-utils/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>datalab</artifactId>
+        <groupId>com.epam.datalab</groupId>
+        <version>1.0</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>datalab-utils</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.dropwizard</groupId>
+            <artifactId>dropwizard-jackson</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>${org.mockito.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/FileUtils.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/FileUtils.java
new file mode 100644
index 0000000..b7bb233
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/FileUtils.java
@@ -0,0 +1,61 @@
+/*
+ * 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.datalab.util;
+
+import com.epam.datalab.exceptions.DatalabException;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+@Slf4j
+public class FileUtils {
+
+    private FileUtils() {
+    }
+
+    public static void saveToFile(String filename, String directory, String content) throws IOException {
+        java.nio.file.Path filePath = Paths.get(directory, filename).toAbsolutePath();
+        log.debug("Saving content to {}", filePath.toString());
+        try {
+            com.google.common.io.Files.createParentDirs(new File(filePath.toString()));
+        } catch (IOException e) {
+            throw new DatalabException("Can't create folder " + filePath + ": " + e.getLocalizedMessage(), e);
+        }
+        Files.write(filePath, content.getBytes());
+    }
+
+    public static void deleteFile(String filename, String directory) throws IOException {
+        java.nio.file.Path filePath = Paths.get(directory, filename).toAbsolutePath();
+        log.debug("Deleting file from {}", filePath.toString());
+        Files.deleteIfExists(filePath);
+    }
+
+    public static void deleteFile(String absolutePath) {
+        log.debug("Deleting file from {}", absolutePath);
+        try {
+            Files.deleteIfExists(Paths.get(absolutePath));
+        } catch (IOException e) {
+            log.error("Problems occured with deleting file {} due to: {}", absolutePath, e.getLocalizedMessage(), e);
+        }
+    }
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/SecurityUtils.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/SecurityUtils.java
new file mode 100644
index 0000000..023c476
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/SecurityUtils.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.util;
+
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class SecurityUtils {
+
+    private static final String PASS_REGEX = "\"password\":\".+?\"";
+    private static final String PASS_REPLACEMENT = "\"password\":\"\\*\\*\\*\"";
+
+    private SecurityUtils() {
+    }
+
+    public static String hideCreds(String... strings) {
+        return Stream.of(strings)
+                .map(str -> str.replaceAll(PASS_REGEX, PASS_REPLACEMENT))
+                .collect(Collectors.joining(" "));
+    }
+
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/ServiceUtils.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/ServiceUtils.java
new file mode 100644
index 0000000..f571692
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/ServiceUtils.java
@@ -0,0 +1,151 @@
+/*
+ * 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.datalab.util;
+
+import com.epam.datalab.exceptions.DatalabException;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+@Slf4j
+public class ServiceUtils {
+
+    private static String includePath = null;
+
+    static {
+        includePath = System.getenv("DATALAB_CONF_DIR");
+        if (includePath == null || includePath.isEmpty()) {
+            includePath = getUserDir();
+        }
+    }
+
+    /* Return working directory.
+     */
+    public static String getUserDir() {
+        return System.getProperty("user.dir");
+    }
+
+    /**
+     * Return path to DataLab configuration directory.
+     *
+     * @return
+     */
+    public static String getConfPath() {
+        return includePath;
+    }
+
+
+    /**
+     * Return manifest for given class or empty manifest if {@link JarFile#MANIFEST_NAME} not found.
+     *
+     * @param clazz class.
+     * @throws IOException
+     */
+    private static Manifest getManifestForClass(Class<?> clazz) throws IOException {
+        URL url = clazz.getClassLoader().getResource(JarFile.MANIFEST_NAME);
+        return (url == null ? new Manifest() : new Manifest(url.openStream()));
+    }
+
+    /**
+     * Return manifest from JAR file.
+     *
+     * @param classPath path to class in JAR file.
+     * @throws IOException
+     */
+    private static Manifest getManifestFromJar(String classPath) throws IOException {
+        URL url = new URL(classPath);
+        JarURLConnection jarConnection = (JarURLConnection) url.openConnection();
+        return jarConnection.getManifest();
+    }
+
+    /**
+     * Return manifest map for given class or empty map if manifest not found or cannot be read.
+     *
+     * @param clazz class.
+     */
+    public static Map<String, String> getManifest(Class<?> clazz) {
+        String className = "/" + clazz.getName().replace('.', '/') + ".class";
+        String classPath = clazz.getResource(className).toString();
+
+        Map<String, String> map = new HashMap<>();
+        try {
+            Manifest manifest = (classPath.startsWith("jar:file:") ? getManifestFromJar(classPath) : getManifestForClass(clazz));
+            Attributes attributes = manifest.getMainAttributes();
+            for (Object key : attributes.keySet()) {
+                map.put(key.toString(), (String) attributes.get(key));
+            }
+        } catch (IOException e) {
+            log.error("Cannot found or open manifest for class {}", className, e);
+            throw new DatalabException("Cannot read manifest file", e);
+        }
+
+        return map;
+    }
+
+    /**
+     * Print to standard output the manifest info about application. If parameter <b>args</b> is not
+     * <b>null</b> and one or more arguments have value -v or --version then print version and return <b>true<b/>
+     * otherwise <b>false</b>.
+     *
+     * @param mainClass the main class of application.
+     * @param args      the arguments of main class function or null.
+     * @return if parameter <b>args</b> is not null and one or more arguments have value -v or --version
+     * then return <b>true<b/> otherwise <b>false</b>.
+     */
+    public static boolean printAppVersion(Class<?> mainClass, String... args) {
+        boolean result = false;
+        if (args != null) {
+            for (String arg : args) {
+                if ("-v".equals(arg) ||
+                        "--version".equals(arg)) {
+                    result = true;
+                }
+            }
+            if (!result) {
+                return result;
+            }
+        }
+
+        Map<String, String> manifest = getManifest(mainClass);
+        if (manifest.isEmpty()) {
+            return result;
+        }
+
+        log.info("Title       {}", manifest.get("Implementation-Title"));
+        log.info("Version     {}", manifest.get("Implementation-Version"));
+        log.info("Created By  {}", manifest.get("Created-By"));
+        log.info("Vendor      {}", manifest.get("Implementation-Vendor"));
+        log.info("GIT-Branch  {}", manifest.get("GIT-Branch"));
+        log.info("GIT-Commit  {}", manifest.get("GIT-Commit"));
+        log.info("Build JDK   {}", manifest.get("Build-Jdk"));
+        log.info("Build OS    {}", manifest.get("Build-OS"));
+        log.info("Built Time  {}", manifest.get("Build-Time"));
+        log.info("Built By    {}", manifest.get("Built-By"));
+
+        return result;
+    }
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/UsernameUtils.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/UsernameUtils.java
new file mode 100644
index 0000000..265f1b2
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/UsernameUtils.java
@@ -0,0 +1,36 @@
+/*
+ * 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.datalab.util;
+
+public class UsernameUtils {
+
+    private static final String UNDERLINE = "_";
+
+    private UsernameUtils() {
+    }
+
+    public static String removeDomain(String username) {
+        return username != null ? username.replaceAll("@.*", "") : null;
+    }
+
+    public static String replaceWhitespaces(String username) {
+        return username.replaceAll("\\s", UNDERLINE);
+    }
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoDateDeSerializer.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoDateDeSerializer.java
new file mode 100644
index 0000000..2406d34
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoDateDeSerializer.java
@@ -0,0 +1,61 @@
+/*
+ * 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.datalab.util.mongo;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.ObjectCodec;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Deserializes {@link java.util.Date} from JSON
+ */
+public class IsoDateDeSerializer extends JsonDeserializer<Date> {
+    static final String DATE_NODE = "$date";
+    static final String ISO_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
+
+    @Override
+    public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
+        ObjectCodec oc = jsonParser.getCodec();
+        JsonNode node = oc.readTree(jsonParser);
+
+        Date date;
+        if (node.get(DATE_NODE) != null) {
+            String dateValue = node.get(DATE_NODE).asText();
+            DateFormat df = new SimpleDateFormat(ISO_DATE_FORMAT);
+            try {
+                date = df.parse(dateValue);
+            } catch (ParseException e) {
+                date = new Date(Long.valueOf(dateValue));
+            }
+        } else {
+            date = new Date(node.asLong());
+        }
+        return date;
+    }
+
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoDateSerializer.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoDateSerializer.java
new file mode 100644
index 0000000..5e88184
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoDateSerializer.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab.util.mongo;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * Serializes the {@link java.util.Date} to JSON
+ */
+public class IsoDateSerializer extends JsonSerializer<Date> {
+
+    @Override
+    public void serialize(Date date, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+        DateFormat df = new SimpleDateFormat(IsoDateDeSerializer.ISO_DATE_FORMAT);
+        df.setTimeZone(TimeZone.getTimeZone("GMT"));
+        String dateValue = df.format(date);
+
+        gen.writeStartObject();
+        gen.writeFieldName(IsoDateDeSerializer.DATE_NODE);
+        gen.writeString(dateValue);
+        gen.writeEndObject();
+    }
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoLocalDateDeSerializer.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoLocalDateDeSerializer.java
new file mode 100644
index 0000000..b050e32
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoLocalDateDeSerializer.java
@@ -0,0 +1,47 @@
+/*
+ * 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.datalab.util.mongo;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.ObjectCodec;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneOffset;
+
+import static com.epam.datalab.util.mongo.IsoDateDeSerializer.DATE_NODE;
+
+public class IsoLocalDateDeSerializer extends JsonDeserializer<LocalDate> {
+    @Override
+    public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+        ObjectCodec oc = p.getCodec();
+        JsonNode node = oc.readTree(p);
+        if (node.get(DATE_NODE) != null) {
+            String dateValue = node.get(DATE_NODE).asText();
+            return Instant.ofEpochMilli(Long.valueOf(dateValue)).atZone(ZoneOffset.systemDefault()).toLocalDate();
+        } else {
+            return Instant.ofEpochMilli(node.asLong()).atZone(ZoneOffset.systemDefault()).toLocalDate();
+        }
+    }
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoLocalDateSerializer.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoLocalDateSerializer.java
new file mode 100644
index 0000000..9fb5e10
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoLocalDateSerializer.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.util.mongo;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+public class IsoLocalDateSerializer extends JsonSerializer<LocalDate> {
+    @Override
+    public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+        gen.writeStartObject();
+        gen.writeFieldName(IsoDateDeSerializer.DATE_NODE);
+        gen.writeString(value.format(DateTimeFormatter.ISO_DATE));
+        gen.writeEndObject();
+    }
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoLocalDateTimeDeSerializer.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoLocalDateTimeDeSerializer.java
new file mode 100644
index 0000000..66876f6
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoLocalDateTimeDeSerializer.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab.util.mongo;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.ObjectCodec;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+import static com.epam.datalab.util.mongo.IsoDateDeSerializer.DATE_NODE;
+
+public class IsoLocalDateTimeDeSerializer extends JsonDeserializer<LocalDateTime> {
+
+    @Override
+    public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+        ObjectCodec oc = p.getCodec();
+        JsonNode node = oc.readTree(p);
+        if (node.get(DATE_NODE) != null) {
+            String dateValue = node.get(DATE_NODE).asText();
+            return Instant.ofEpochMilli(Long.valueOf(dateValue)).atZone(ZoneOffset.systemDefault()).toLocalDateTime();
+        } else {
+            return Instant.ofEpochMilli(node.asLong()).atZone(ZoneOffset.systemDefault()).toLocalDateTime();
+        }
+    }
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerializer.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerializer.java
new file mode 100644
index 0000000..6613279
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerializer.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.util.mongo;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class IsoLocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
+    @Override
+    public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+        gen.writeStartObject();
+        gen.writeFieldName(IsoDateDeSerializer.DATE_NODE);
+        gen.writeString(value.format(DateTimeFormatter.ISO_DATE_TIME));
+        gen.writeEndObject();
+    }
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/LongDeSerializer.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/LongDeSerializer.java
new file mode 100644
index 0000000..0652aeb
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/LongDeSerializer.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.util.mongo;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.ObjectCodec;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.io.IOException;
+
+public class LongDeSerializer extends JsonDeserializer<Long> {
+    private static final String NUMBER_NODE = "$numberLong";
+
+    @Override
+    public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+        ObjectCodec oc = p.getCodec();
+        JsonNode node = oc.readTree(p);
+
+        final JsonNode numberNode = node.get(NUMBER_NODE);
+        if (numberNode != null) {
+            return numberNode.asLong();
+        } else {
+            return node.asLong();
+        }
+    }
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/MongoStringDeserializer.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/MongoStringDeserializer.java
new file mode 100644
index 0000000..06c2972
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/MongoStringDeserializer.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.datalab.util.mongo;
+
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.KeyDeserializer;
+
+import static com.epam.datalab.util.mongo.MongoStringSerializaer.DOT_UNICODE;
+
+public class MongoStringDeserializer extends KeyDeserializer {
+
+    @Override
+    public Object deserializeKey(String key, DeserializationContext ctxt) {
+        return key.contains(DOT_UNICODE) ? key.replace(DOT_UNICODE, ".") : key;
+    }
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/MongoStringSerializaer.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/MongoStringSerializaer.java
new file mode 100644
index 0000000..f991758
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/MongoStringSerializaer.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.util.mongo;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import java.io.IOException;
+
+public class MongoStringSerializaer extends JsonSerializer<String> {
+    public static final String DOT_UNICODE = "U+FF0E";
+
+    @Override
+    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+        if (value.contains(".")) {
+            gen.writeFieldName(value.replace(".", DOT_UNICODE));
+        } else {
+            gen.writeFieldName(value);
+        }
+    }
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/modules/IsoDateModule.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/modules/IsoDateModule.java
new file mode 100644
index 0000000..398f8cb
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/modules/IsoDateModule.java
@@ -0,0 +1,64 @@
+/*
+ * 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.datalab.util.mongo.modules;
+
+import com.epam.datalab.util.mongo.IsoDateDeSerializer;
+import com.epam.datalab.util.mongo.IsoDateSerializer;
+import com.epam.datalab.util.mongo.IsoLocalDateDeSerializer;
+import com.epam.datalab.util.mongo.IsoLocalDateSerializer;
+import com.epam.datalab.util.mongo.IsoLocalDateTimeDeSerializer;
+import com.epam.datalab.util.mongo.IsoLocalDateTimeSerializer;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.fasterxml.jackson.datatype.jsr310.deser.JSR310StringParsableDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneOffset;
+import java.util.Date;
+
+/**
+ * Serialization/Deserialization modul for {@link java.util.Date} that uses {@link IsoDateDeSerializer} and
+ * {@link IsoDateSerializer}
+ */
+public class IsoDateModule extends SimpleModule {
+	private static final long serialVersionUID = -2103066255354028256L;
+
+	public IsoDateModule() {
+		super();
+		addSerializer(Date.class, new IsoDateSerializer());
+		addDeserializer(Date.class, new IsoDateDeSerializer());
+
+		addSerializer(LocalDate.class, new IsoLocalDateSerializer());
+		addDeserializer(LocalDate.class, new IsoLocalDateDeSerializer());
+
+		addSerializer(LocalTime.class, new ToStringSerializer(LocalTime.class));
+		addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE);
+
+		addSerializer(LocalDateTime.class, new IsoLocalDateTimeSerializer());
+		addDeserializer(LocalDateTime.class, new IsoLocalDateTimeDeSerializer());
+
+		addSerializer(ZoneOffset.class, new ToStringSerializer(ZoneOffset.class));
+		addDeserializer(ZoneOffset.class, JSR310StringParsableDeserializer.ZONE_OFFSET);
+
+	}
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/modules/JavaPrimitiveModule.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/modules/JavaPrimitiveModule.java
new file mode 100644
index 0000000..681820a
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/modules/JavaPrimitiveModule.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.datalab.util.mongo.modules;
+
+import com.epam.datalab.util.mongo.LongDeSerializer;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+public class JavaPrimitiveModule extends SimpleModule {
+
+    public JavaPrimitiveModule() {
+        addDeserializer(Long.class, new LongDeSerializer());
+    }
+
+}
diff --git a/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/modules/MongoModule.java b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/modules/MongoModule.java
new file mode 100644
index 0000000..e6aaae2
--- /dev/null
+++ b/services/datalab-utils/src/main/java/com/epam/datalab/util/mongo/modules/MongoModule.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.datalab.util.mongo.modules;
+
+import com.epam.datalab.util.mongo.MongoStringDeserializer;
+import com.epam.datalab.util.mongo.MongoStringSerializaer;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+public class MongoModule extends SimpleModule {
+
+    public MongoModule() {
+        addKeySerializer(String.class, new MongoStringSerializaer());
+        addKeyDeserializer(String.class, new MongoStringDeserializer());
+    }
+}
diff --git a/services/datalab-utils/src/test/java/com/epam/datalab/util/SecurityUtilsTest.java b/services/datalab-utils/src/test/java/com/epam/datalab/util/SecurityUtilsTest.java
new file mode 100644
index 0000000..390a79b
--- /dev/null
+++ b/services/datalab-utils/src/test/java/com/epam/datalab/util/SecurityUtilsTest.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SecurityUtilsTest {
+
+    @Test
+    public void hideCredsTest() {
+        String[] strings = {"bash", "-c", "\"edge_user_name\":\"edgeUserName\",\"conf_service_base_name\":\"SBN\", " +
+                "\"password\":\"12345\""};
+        String actual = SecurityUtils.hideCreds(strings);
+        String expected = "bash -c \"edge_user_name\":\"edgeUserName\",\"conf_service_base_name\":\"SBN\", " +
+                "\"password\":\"***\"";
+        Assert.assertEquals(expected, actual);
+    }
+}
diff --git a/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeDeSerializerTest.java b/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeDeSerializerTest.java
new file mode 100644
index 0000000..12c0222
--- /dev/null
+++ b/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeDeSerializerTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.datalab.util.mongo;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.ObjectCodec;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.io.IOException;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class IsoLocalDateTimeDeSerializerTest {
+
+    @Test
+    public void deserialize() throws IOException {
+        JsonParser jsonParser = mock(JsonParser.class);
+        DeserializationContext ctxt = mock(DeserializationContext.class);
+
+        ObjectCodec objectCodec = mock(ObjectCodec.class);
+        when(jsonParser.getCodec()).thenReturn(objectCodec);
+
+        JsonNode jsonNode = mock(JsonNode.class);
+        when(objectCodec.readTree(jsonParser)).thenReturn(jsonNode);
+
+        JsonNode jsonNode2 = mock(JsonNode.class);
+        when(jsonNode.get(anyString())).thenReturn(jsonNode2);
+        when(jsonNode2.asText()).thenReturn("1234567890");
+
+        new IsoLocalDateTimeDeSerializer().deserialize(jsonParser, ctxt);
+
+        verify(jsonParser).getCodec();
+        verify(objectCodec).readTree(jsonParser);
+        verify(jsonNode, times(2)).get("$date");
+        verify(jsonNode2).asText();
+        verify(jsonNode, never()).asLong();
+        verifyNoMoreInteractions(jsonParser, objectCodec, jsonNode, jsonNode2);
+    }
+
+    @Test
+    public void deserializeWhenMethodGetReturnsNull() throws IOException {
+        JsonParser jsonParser = mock(JsonParser.class);
+        DeserializationContext ctxt = mock(DeserializationContext.class);
+
+        ObjectCodec objectCodec = mock(ObjectCodec.class);
+        when(jsonParser.getCodec()).thenReturn(objectCodec);
+
+        JsonNode jsonNode = mock(JsonNode.class);
+        when(objectCodec.readTree(jsonParser)).thenReturn(jsonNode);
+
+        when(jsonNode.get(anyString())).thenReturn(null);
+
+        new IsoLocalDateTimeDeSerializer().deserialize(jsonParser, ctxt);
+
+        verify(jsonParser).getCodec();
+        verify(objectCodec).readTree(jsonParser);
+        verify(jsonNode).get("$date");
+        verify(jsonNode).asLong();
+        verifyNoMoreInteractions(jsonParser, objectCodec, jsonNode);
+    }
+}
\ No newline at end of file
diff --git a/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerDeTest.java b/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerDeTest.java
new file mode 100644
index 0000000..391238a
--- /dev/null
+++ b/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerDeTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.datalab.util.mongo;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+
+import static org.junit.Assert.assertEquals;
+
+public class IsoLocalDateTimeSerDeTest {
+
+    private static ObjectMapper objectMapper;
+
+    @BeforeClass
+    public static void setup() {
+        objectMapper = new ObjectMapper();
+    }
+
+    @Test
+    public void shoudProperlySerializeLocalDateTimeToJson() throws JsonProcessingException {
+        String actual = objectMapper.writeValueAsString(new SampleClass());
+        assertEquals("{\"localDateTime\":{\"$date\":\"2018-04-10T15:30:45\"}}", actual);
+    }
+
+    @Test
+    public void shoudProperlyDeserializeLocalDateTimeFromJson() throws IOException {
+        LocalDateTime now = LocalDateTime.now();
+        long l = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
+        SampleClass actual = objectMapper
+                .readValue("{\"localDateTime\":{\"$date\":" + l + "}}", SampleClass.class);
+
+        assertEquals(now, actual.getLocalDateTime());
+    }
+
+    private static class SampleClass {
+
+        @JsonSerialize(using = IsoLocalDateTimeSerializer.class)
+        @JsonDeserialize(using = IsoLocalDateTimeDeSerializer.class)
+        private final LocalDateTime localDateTime = LocalDateTime.parse("2018-04-10T15:30:45");
+
+        LocalDateTime getLocalDateTime() {
+            return localDateTime;
+        }
+    }
+}
diff --git a/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerializerTest.java b/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerializerTest.java
new file mode 100644
index 0000000..d50869a
--- /dev/null
+++ b/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerializerTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.datalab.util.mongo;
+
+import com.fasterxml.jackson.databind.SerializerProvider;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+@RunWith(MockitoJUnitRunner.class)
+public class IsoLocalDateTimeSerializerTest {
+
+    @Test
+    public void serialize() throws IOException {
+        com.fasterxml.jackson.core.JsonGenerator jsonGenerator = mock(com.fasterxml.jackson.core.JsonGenerator.class);
+        SerializerProvider serializerProvider = mock(SerializerProvider.class);
+
+        LocalDateTime localDateTime = LocalDateTime.now();
+
+        new IsoLocalDateTimeSerializer().serialize(localDateTime, jsonGenerator, serializerProvider);
+
+        verify(jsonGenerator).writeStartObject();
+        verify(jsonGenerator).writeFieldName("$date");
+        verify(jsonGenerator).writeString(localDateTime.format(DateTimeFormatter.ISO_DATE_TIME));
+        verify(jsonGenerator).writeEndObject();
+        verifyNoMoreInteractions(jsonGenerator);
+        verifyZeroInteractions(serializerProvider);
+    }
+
+
+}
\ No newline at end of file
diff --git a/services/datalab-webapp-common/pom.xml b/services/datalab-webapp-common/pom.xml
new file mode 100644
index 0000000..a89c115
--- /dev/null
+++ b/services/datalab-webapp-common/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>datalab</artifactId>
+        <groupId>com.epam.datalab</groupId>
+        <version>1.0</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>datalab-webapp-common</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.mongodb</groupId>
+            <artifactId>mongo-java-driver</artifactId>
+            <version>${org.mongodb.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.inject</groupId>
+            <artifactId>guice</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.dropwizard</groupId>
+            <artifactId>dropwizard-jackson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.dropwizard</groupId>
+            <artifactId>dropwizard-auth</artifactId>
+            <version>${io.dropwizard.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.dropwizard</groupId>
+            <artifactId>dropwizard-client</artifactId>
+            <version>${io.dropwizard.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.dropwizard</groupId>
+            <artifactId>dropwizard-forms</artifactId>
+            <version>${io.dropwizard.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>common</artifactId>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/ModuleBase.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/ModuleBase.java
new file mode 100644
index 0000000..df6cebc
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/ModuleBase.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab;
+
+import com.google.inject.AbstractModule;
+import io.dropwizard.setup.Environment;
+
+/**
+ * The base class for an application configuration of service.
+ */
+public abstract class ModuleBase<T extends ServiceConfiguration> extends AbstractModule {
+    /**
+     * Application configuration of service.
+     */
+    protected T configuration;
+    /**
+     * Environment of service.
+     */
+    protected Environment environment;
+
+    /**
+     * Instantiates an application configuration of service.
+     *
+     * @param configuration application configuration of service.
+     * @param environment   environment of service.
+     */
+    public ModuleBase(T configuration, Environment environment) {
+        this.configuration = configuration;
+        this.environment = environment;
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/ServiceConfiguration.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/ServiceConfiguration.java
new file mode 100644
index 0000000..7d4ead2
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/ServiceConfiguration.java
@@ -0,0 +1,114 @@
+/*
+ * 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.datalab;
+
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.mongo.MongoServiceFactory;
+import com.epam.datalab.rest.client.RESTServiceFactory;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.dropwizard.Configuration;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+public class ServiceConfiguration extends Configuration {
+
+    @JsonProperty
+    private long inactiveUserTimeoutMillSec = 2 * 60L * 60L * 1000L;
+
+    @NotNull
+    @JsonProperty
+    private CloudProvider cloudProvider;
+
+    @Valid
+    @JsonProperty
+    private boolean devMode = false;
+
+    @Valid
+    @NotNull
+    @JsonProperty(ServiceConsts.MONGO_NAME)
+    private MongoServiceFactory mongoFactory = new MongoServiceFactory();
+
+    @Valid
+    @NotNull
+    @JsonProperty(ServiceConsts.PROVISIONING_SERVICE_NAME)
+    private RESTServiceFactory provisioningFactory = new RESTServiceFactory();
+
+    @Valid
+    @NotNull
+    @JsonProperty(ServiceConsts.BUCKET_SERVICE_NAME)
+    private RESTServiceFactory bucketFactory = new RESTServiceFactory();
+
+    @Valid
+    @NotNull
+    @JsonProperty(ServiceConsts.BILLING_SERVICE_NAME)
+    private RESTServiceFactory billingFactory = new RESTServiceFactory();
+
+    @Valid
+    @NotNull
+    @JsonProperty(ServiceConsts.SECURITY_SERVICE_NAME)
+    private RESTServiceFactory securityFactory;
+
+    @Valid
+    @NotNull
+    @JsonProperty(ServiceConsts.SELF_SERVICE_NAME)
+    private RESTServiceFactory selfFactory = new RESTServiceFactory();
+
+    public CloudProvider getCloudProvider() {
+        return cloudProvider;
+    }
+
+    public long getInactiveUserTimeoutMillSec() {
+        return inactiveUserTimeoutMillSec;
+    }
+
+    /**
+     * Returns <b>true</b> if service is a mock.
+     */
+    public boolean isDevMode() {
+        return devMode;
+    }
+
+    public MongoServiceFactory getMongoFactory() {
+        return mongoFactory;
+    }
+
+    public RESTServiceFactory getProvisioningFactory() {
+        return provisioningFactory;
+    }
+
+    public RESTServiceFactory getBucketFactory() {
+        return bucketFactory;
+    }
+
+    public RESTServiceFactory getBillingFactory() {
+        return billingFactory;
+    }
+
+    public RESTServiceFactory getSecurityFactory() {
+        return securityFactory;
+    }
+
+    public RESTServiceFactory getSelfFactory() {
+        return selfFactory;
+    }
+
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/SecurityUnauthorizedHandler.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/SecurityUnauthorizedHandler.java
new file mode 100644
index 0000000..b74be0a
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/SecurityUnauthorizedHandler.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.datalab.auth;
+
+import io.dropwizard.auth.UnauthorizedHandler;
+
+import javax.ws.rs.core.Response;
+
+public class SecurityUnauthorizedHandler implements UnauthorizedHandler {
+    @Override
+    public Response buildResponse(String prefix, String realm) {
+        return Response.status(Response.Status.UNAUTHORIZED).build();
+    }
+
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/UserInfo.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/UserInfo.java
new file mode 100644
index 0000000..af5360d
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/UserInfo.java
@@ -0,0 +1,222 @@
+/*
+ * 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.datalab.auth;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSetter;
+
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UserInfo implements Principal {
+
+    private final String username;
+    private final String accessToken;
+    private String refreshToken;
+    private final Set<String> roles = new HashSet<>();
+    private final Map<String, String> keys = new HashMap<>();
+
+    @JsonProperty
+    private String firstName;
+    @JsonProperty
+    private String lastName;
+    @JsonProperty
+    private String remoteIp;
+    @JsonProperty
+    private boolean awsUser = false;
+
+    @JsonCreator
+    public UserInfo(@JsonProperty("username") String username,
+                    @JsonProperty("access_token") String accessToken) {
+        this.username = (username == null ? null : username.toLowerCase());
+        this.accessToken = accessToken;
+    }
+
+    @Override
+    @JsonProperty("username")
+    public String getName() {
+        return username;
+    }
+
+    public String getSimpleName() {
+        return (username == null ? null : username.replaceAll("@.*", ""));
+    }
+
+    @JsonProperty("access_token")
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    @JsonProperty("refresh_token")
+    public String getRefreshToken() {
+        return refreshToken;
+    }
+
+    public void setRefreshToken(String refreshToken) {
+        this.refreshToken = refreshToken;
+    }
+
+    @JsonProperty("roles")
+    public Set<String> getRoles() {
+        return roles;
+    }
+
+    //@JsonSetter("roles")
+    public void addRoles(Collection<String> r) {
+        roles.addAll(r);
+    }
+
+    @JsonSetter("roles")
+    public void addRoles(String[] r) {
+        roles.addAll(Arrays.asList(r));
+    }
+
+    public void addRole(String role) {
+        roles.add(role);
+    }
+
+
+    public String getFirstName() {
+        return firstName;
+    }
+
+    public void setFirstName(String firstName) {
+        this.firstName = firstName;
+    }
+
+    public String getLastName() {
+        return lastName;
+    }
+
+    public void setLastName(String lastName) {
+        this.lastName = lastName;
+    }
+
+    public String getRemoteIp() {
+        return remoteIp;
+    }
+
+    public void setRemoteIp(String remoteIp) {
+        this.remoteIp = remoteIp;
+    }
+
+    public UserInfo withToken(String token) {
+        UserInfo newInfo = new UserInfo(username, token);
+        roles.forEach(newInfo::addRole);
+        newInfo.firstName = this.firstName;
+        newInfo.lastName = this.lastName;
+        newInfo.remoteIp = this.remoteIp;
+        newInfo.awsUser = this.awsUser;
+        newInfo.setKeys(this.getKeys());
+        return newInfo;
+    }
+
+    public boolean isAwsUser() {
+        return awsUser;
+    }
+
+    public void setAwsUser(boolean awsUser) {
+        this.awsUser = awsUser;
+    }
+
+    public Map<String, String> getKeys() {
+        return keys;
+    }
+
+    public void addKey(String id, String status) {
+        keys.put(id, status);
+    }
+
+    @JsonSetter("keys")
+    public void setKeys(Map<String, String> awsKeys) {
+        awsKeys.forEach(keys::put);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        UserInfo userInfo = (UserInfo) o;
+
+        if (awsUser != userInfo.awsUser) {
+            return false;
+        }
+        if (username != null ? !username.equals(userInfo.username) : userInfo.username != null) {
+            return false;
+        }
+        if (accessToken != null ? !accessToken.equals(userInfo.accessToken) : userInfo.accessToken != null)
+            return false;
+        if (!roles.equals(userInfo.roles)) {
+            return false;
+        }
+        if (!keys.equals(userInfo.keys)) {
+            return false;
+        }
+        if (firstName != null ? !firstName.equals(userInfo.firstName) : userInfo.firstName != null) {
+            return false;
+        }
+        if (lastName != null ? !lastName.equals(userInfo.lastName) : userInfo.lastName != null) {
+            return false;
+        }
+        return remoteIp != null ? remoteIp.equals(userInfo.remoteIp) : userInfo.remoteIp == null;
+    }
+
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(username,
+                accessToken,
+                roles,
+                keys,
+                firstName,
+                lastName,
+                remoteIp,
+                awsUser);
+    }
+
+    @Override
+    public String toString() {
+        return "UserInfo{" +
+                "username='" + username + '\'' +
+                ", accessToken='" + accessToken + '\'' +
+                ", refreshToken='" + refreshToken + '\'' +
+                ", roles=" + roles +
+                ", keys=" + keys.keySet() +
+                ", firstName='" + firstName + '\'' +
+                ", lastName='" + lastName + '\'' +
+                ", remoteIp='" + remoteIp + '\'' +
+                ", awsUser=" + awsUser +
+                '}';
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/contract/SecurityAPI.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/contract/SecurityAPI.java
new file mode 100644
index 0000000..cddbb7a
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/contract/SecurityAPI.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.datalab.auth.contract;
+
+public interface SecurityAPI {
+	String LOGIN = "login";
+	String LOGIN_OAUTH = LOGIN + '/' + "oauth";
+	String LOGIN_OAUTH_AZURE = "user/azure/oauth";
+	String GET_USER_INFO = "getuserinfo";
+	String LOGOUT = "logout";
+	String INIT_LOGIN_OAUTH_AZURE = "/user/azure/init";
+	String INIT_LOGIN_OAUTH_GCP = "/user/gcp/init";
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/dto/UserCredentialDTO.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/dto/UserCredentialDTO.java
new file mode 100644
index 0000000..c9b393a
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/dto/UserCredentialDTO.java
@@ -0,0 +1,74 @@
+/*
+ * 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.datalab.auth.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.hibernate.validator.constraints.NotBlank;
+
+public class UserCredentialDTO {
+    @NotBlank
+    @JsonProperty
+    private String username;
+
+    @NotBlank
+    @JsonProperty
+    private String password;
+
+    @JsonProperty("access_token")
+    private String accessToken;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = (username == null ? null : username.toLowerCase());
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("username", username)
+                .add("password", password == null ? null : "***")
+                .add("accessToken", accessToken == null ? null : "***");
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/oauth2/Oauth2AuthenticationService.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/oauth2/Oauth2AuthenticationService.java
new file mode 100644
index 0000000..9d5084f
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/oauth2/Oauth2AuthenticationService.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.auth.oauth2;
+
+public interface Oauth2AuthenticationService {
+
+    /**
+     * @return redirected ulr
+     */
+    String getRedirectedUrl();
+
+    /**
+     * Authorize user using oauth authorization code
+     *
+     * @param code  authorization code
+     * @param state state
+     * @return token
+     */
+    String authorize(String code, String state);
+
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/rest/AbstractAuthenticationService.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/rest/AbstractAuthenticationService.java
new file mode 100644
index 0000000..c969c68
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/rest/AbstractAuthenticationService.java
@@ -0,0 +1,47 @@
+/*
+ * 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.datalab.auth.rest;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.auth.dto.UserCredentialDTO;
+import io.dropwizard.Configuration;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Response;
+import java.util.UUID;
+
+public abstract class AbstractAuthenticationService<C extends Configuration> extends ConfigurableResource<C> {
+
+    public AbstractAuthenticationService(C config) {
+        super(config);
+    }
+
+    public static String getRandomToken() {
+        return UUID.randomUUID().toString();
+    }
+
+    public abstract Response login(UserCredentialDTO credential, HttpServletRequest request);
+
+    public abstract UserInfo getUserInfo(String accessToken, HttpServletRequest request);
+
+    public abstract Response logout(String accessToken);
+
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/rest/ConfigurableResource.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/rest/ConfigurableResource.java
new file mode 100644
index 0000000..d3d3e79
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/rest/ConfigurableResource.java
@@ -0,0 +1,36 @@
+/*
+ * 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.datalab.auth.rest;
+
+import io.dropwizard.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class ConfigurableResource<C extends Configuration> {
+
+    protected final Logger log;
+    protected final C config;
+
+    public ConfigurableResource(C config) {
+        this.log = LoggerFactory.getLogger(getClass());
+        this.config = config;
+    }
+
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/rest/UserSessionDurationAuthorizer.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/rest/UserSessionDurationAuthorizer.java
new file mode 100644
index 0000000..90d8b2b
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/rest/UserSessionDurationAuthorizer.java
@@ -0,0 +1,90 @@
+/*
+ * 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.datalab.auth.rest;
+
+import com.epam.datalab.auth.UserInfo;
+import io.dropwizard.auth.Authorizer;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Date;
+
+@Slf4j
+public final class UserSessionDurationAuthorizer implements Authorizer<UserInfo> {
+    public static final String SHORT_USER_SESSION_DURATION = "SHORT_USER_SESSION";
+    private final long maxSessionDurabilityMilliseconds;
+    private UserSessionDurationCallback callback;
+
+    public UserSessionDurationAuthorizer(UserSessionDurationCallback callback, long maxSessionDurabilityMilliseconds) {
+        this.callback = callback;
+        this.maxSessionDurabilityMilliseconds = maxSessionDurabilityMilliseconds;
+    }
+
+    @Override
+    public boolean authorize(UserInfo principal, String role) {
+        if (SHORT_USER_SESSION_DURATION.equalsIgnoreCase(role)) {
+            try {
+                String refreshToken = principal.getKeys().get("refresh_token");
+                String createdDateOfRefreshToken = principal.getKeys().get("created_date_of_refresh_token");
+
+                if (StringUtils.isEmpty(refreshToken)) {
+                    log.info("Refresh token is empty for user {}", principal.getName());
+                    return false;
+                }
+
+                if (StringUtils.isEmpty(createdDateOfRefreshToken)) {
+                    log.info("Created date for refresh token is empty for user {}", principal.getName());
+                    return false;
+                }
+
+                log.debug("refresh token requested {} and current date is {}",
+                        new Date(Long.valueOf(createdDateOfRefreshToken)), new Date());
+
+                long passedTime = System.currentTimeMillis() - Long.valueOf(createdDateOfRefreshToken);
+
+                log.info("Passed time of session for user {} is {} milliseconds", principal.getName(), passedTime);
+                if (passedTime > maxSessionDurabilityMilliseconds) {
+
+                    silentCallbackExecution(principal);
+
+                    log.info("Re-login required for user {}", principal.getName());
+                    return false;
+                }
+
+                return true;
+            } catch (RuntimeException e) {
+                log.error("Cannot verify durability of session for user {}", principal.getName(), e);
+                return false;
+            }
+
+        }
+
+        return true;
+    }
+
+    private void silentCallbackExecution(UserInfo principal) {
+        log.info("Log out expired user {}", principal.getName());
+        try {
+            callback.onSessionExpired(principal);
+        } catch (RuntimeException e) {
+            log.warn("Error during logout user {}", principal.getName(), e);
+        }
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/rest/UserSessionDurationCallback.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/rest/UserSessionDurationCallback.java
new file mode 100644
index 0000000..c3de925
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/auth/rest/UserSessionDurationCallback.java
@@ -0,0 +1,27 @@
+/*
+ * 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.datalab.auth.rest;
+
+import com.epam.datalab.auth.UserInfo;
+
+@FunctionalInterface
+public interface UserSessionDurationCallback {
+    void onSessionExpired(UserInfo userInfo);
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/cloud/CloudModule.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/cloud/CloudModule.java
new file mode 100644
index 0000000..7be15b1
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/cloud/CloudModule.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab.cloud;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Injector;
+import io.dropwizard.setup.Environment;
+
+public abstract class CloudModule extends AbstractModule {
+
+    @Override
+    protected void configure() {
+    }
+
+    public abstract void init(Environment environment, Injector injector);
+
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/cloud/CloudProvider.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/cloud/CloudProvider.java
new file mode 100644
index 0000000..e139262
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/cloud/CloudProvider.java
@@ -0,0 +1,28 @@
+/*
+ * 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.datalab.cloud;
+
+public enum CloudProvider {
+    AWS, AZURE, GCP;
+
+    public String getName() {
+        return this.toString().toLowerCase();
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/constants/ServiceConsts.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/constants/ServiceConsts.java
new file mode 100644
index 0000000..c9c4b62
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/constants/ServiceConsts.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab.constants;
+
+public final class ServiceConsts {
+    public static final String MONGO_NAME = "mongo";
+    public static final String PROVISIONING_SERVICE_NAME = "provisioningService";
+    public static final String BILLING_SERVICE_NAME = "billingService";
+    public static final String BUCKET_SERVICE_NAME = "bucketService";
+    public static final String MAVEN_SEARCH_API = "mavenSearchService";
+    public static final String SECURITY_SERVICE_NAME = "securityService";
+    public static final String SELF_SERVICE_NAME = "selfService";
+    public static final String PROVISIONING_USER_AGENT = "provisioning-service";
+
+    private ServiceConsts() {
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/mongo/MongoService.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/mongo/MongoService.java
new file mode 100644
index 0000000..b8b8055
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/mongo/MongoService.java
@@ -0,0 +1,80 @@
+/*
+ * 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.datalab.mongo;
+
+import com.mongodb.MongoClient;
+import com.mongodb.WriteConcern;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
+import org.bson.Document;
+
+public class MongoService {
+    private MongoClient client;
+    private String databaseName;
+    private MongoDatabase database;
+
+    private static final Document PING = new Document("ping", "1");
+
+    public MongoService(MongoClient client,
+                        String databaseName,
+                        WriteConcern writeConcern) {
+        this(client, databaseName);
+        database = database.withWriteConcern(writeConcern);
+    }
+
+    public MongoService(MongoClient client, String databaseName) {
+        this.client = client;
+        this.databaseName = databaseName;
+        this.database = client.getDatabase(databaseName);
+    }
+
+    public boolean collectionExists(String name) {
+        for (String c : database.listCollectionNames()) {
+            if (c.equals(name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public MongoCollection<Document> getCollection(String name) {
+        return database.getCollection(name, Document.class);
+    }
+
+    public <T> MongoCollection<T> getCollection(String name, Class<T> c) {
+        return database.getCollection(name, c);
+    }
+
+    public void createCollection(String name) {
+        database.createCollection(name);
+    }
+
+    public String getDatabaseName() {
+        return databaseName;
+    }
+
+    public MongoClient getClient() {
+        return client;
+    }
+
+    public Document ping() {
+        return database.runCommand(PING);
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/mongo/MongoServiceFactory.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/mongo/MongoServiceFactory.java
new file mode 100644
index 0000000..fbb213e
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/mongo/MongoServiceFactory.java
@@ -0,0 +1,93 @@
+/*
+ * 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.datalab.mongo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.mongodb.MongoClient;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
+import io.dropwizard.lifecycle.Managed;
+import io.dropwizard.setup.Environment;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import java.util.Collections;
+
+// TODO: Separate configuration and factory responsibilities
+public class MongoServiceFactory {
+    @NotEmpty
+    @JsonProperty
+    private String host;
+
+    @Min(1)
+    @Max(65535)
+    @JsonProperty
+    private int port;
+
+    @NotEmpty
+    @JsonProperty
+    private String username;
+
+    @NotEmpty
+    @JsonProperty
+    private String password;
+
+    @NotEmpty
+    @JsonProperty
+    private String database;
+
+    public MongoService build(Environment environment) {
+        MongoClient client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(
+                MongoCredential.createCredential(username, database, password.toCharArray())
+        ));
+        environment.lifecycle().manage(new Managed() {
+            @Override
+            public void start() {
+            }
+
+            @Override
+            public void stop() {
+                client.close();
+            }
+        });
+        return new MongoService(client, database);
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public String getDatabase() {
+        return database;
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/client/RESTService.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/client/RESTService.java
new file mode 100644
index 0000000..a2d502d
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/client/RESTService.java
@@ -0,0 +1,165 @@
+/*
+ * 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.datalab.rest.client;
+
+import lombok.extern.slf4j.Slf4j;
+import org.glassfish.jersey.media.multipart.Boundary;
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import java.net.URI;
+import java.util.Collections;
+import java.util.Map;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA_TYPE;
+
+@Slf4j
+public class RESTService {
+    private Client client;
+    private String url;
+    private String userAgent;
+
+    public RESTService() {
+    }
+
+    RESTService(Client client, String url, String userAgent) {
+        this.client = client;
+        this.url = url;
+        this.userAgent = userAgent;
+    }
+
+    RESTService(Client client, String userAgent) {
+        this.client = client;
+        this.userAgent = userAgent;
+    }
+
+    public <T> T get(String path, Class<T> clazz) {
+        return get(path, null, clazz);
+    }
+
+    public <T> T get(URI path, Class<T> clazz) {
+        log.debug("REST get {}", path);
+        return client.target(URI.create(url + path.toString()))
+                .request()
+                .get(clazz);
+    }
+
+    public <T> T getWithMediaTypes(String path, String accessToken, Class<T> clazz, String requestMediaType, String acceptMediaType) {
+        return get(path, accessToken, clazz, requestMediaType, acceptMediaType);
+    }
+
+    public <T> T get(String path, String accessToken, Class<T> clazz) {
+        return get(path, accessToken, clazz, APPLICATION_JSON, APPLICATION_JSON);
+    }
+
+    private <T> T get(String path, String accessToken, Class<T> clazz, String requestMediaType, String acceptMediaType) {
+        Invocation.Builder builder = getBuilder(path, accessToken, Collections.emptyMap(), requestMediaType, acceptMediaType);
+        log.debug("REST get secured {} {}", path, accessToken);
+        return builder.get(clazz);
+    }
+
+    public <T> T get(String path, GenericType<T> genericType) {
+        return get(path, null, genericType);
+    }
+
+    public <T> T get(String path, String accessToken, GenericType<T> genericType) {
+        return get(path, accessToken, genericType, Collections.emptyMap());
+    }
+
+    public <T> T get(String path, String accessToken, GenericType<T> genericType, Map<String, Object> queryParams) {
+        Invocation.Builder builder = getBuilder(path, accessToken, queryParams, APPLICATION_JSON, APPLICATION_JSON);
+        log.debug("REST get secured {} {}", path, accessToken);
+        return builder.get(genericType);
+    }
+
+    public <T> T post(String path, Object parameter, Class<T> clazz) {
+        return post(path, null, parameter, clazz);
+    }
+
+    public <T> T post(String path, String accessToken, Object parameter, Class<T> clazz) {
+        return post(path, accessToken, parameter, clazz, Collections.emptyMap(), APPLICATION_JSON, APPLICATION_JSON);
+    }
+
+    public <T> T delete(String path, String accessToken, Class<T> clazz, String requestMediaType, String acceptMediaType) {
+        return delete(path, accessToken, clazz, Collections.emptyMap(), requestMediaType, acceptMediaType);
+    }
+
+    private <T> T delete(String path, String accessToken, Class<T> clazz, Map<String, Object> queryParams,
+                         String requestMediaType, String acceptMediaType) {
+        Invocation.Builder builder = getBuilder(path, accessToken, queryParams, requestMediaType, acceptMediaType);
+        log.debug("REST delete secured {} {}", path, accessToken);
+        return builder.delete(clazz);
+    }
+
+    private <T> T post(String path, String accessToken, Object parameter, Class<T> clazz, Map<String, Object> queryParams,
+                       String requestMediaType, String acceptMediaType) {
+        Invocation.Builder builder = getBuilder(path, accessToken, queryParams, requestMediaType, acceptMediaType);
+        log.debug("REST post secured {} {}", path, accessToken);
+        return builder.post(Entity.json(parameter), clazz);
+    }
+
+
+    private Invocation.Builder getBuilder(String path, String token, Map<String, Object> queryParams,
+                                          String requestMediaType, String acceptMediaType) {
+        WebTarget webTarget = getWebTarget(path);
+        for (Map.Entry<String, Object> entry : queryParams.entrySet()) {
+            webTarget = webTarget.queryParam(entry.getKey(), entry.getValue());
+        }
+
+        Invocation.Builder builder = webTarget
+                .request(requestMediaType)
+                .accept(acceptMediaType);
+
+        if (token != null) {
+            builder.header(HttpHeaders.AUTHORIZATION, "Bearer " + token);
+        }
+        if (userAgent != null) {
+            builder.header(HttpHeaders.USER_AGENT, userAgent);
+        }
+
+        return builder;
+    }
+
+    public <T> T postForm(String path, String token, FormDataMultiPart form, Class<T> clazz) {
+        WebTarget webTarget = getWebTarget(path);
+        Invocation.Builder builder = webTarget.request();
+        if (token != null) {
+            builder.header(HttpHeaders.AUTHORIZATION, "Bearer " + token);
+        }
+        if (userAgent != null) {
+            builder.header(HttpHeaders.USER_AGENT, userAgent);
+        }
+
+        MediaType mediaType = Boundary.addBoundary(MULTIPART_FORM_DATA_TYPE);
+        return builder.post(Entity.entity(form, mediaType), clazz);
+    }
+
+
+    private WebTarget getWebTarget(String path) {
+        return url != null ? client.target(url).path(path) : client.target(path);
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/client/RESTServiceFactory.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/client/RESTServiceFactory.java
new file mode 100644
index 0000000..cfc5269
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/client/RESTServiceFactory.java
@@ -0,0 +1,61 @@
+/*
+ * 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.datalab.rest.client;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.dropwizard.client.JerseyClientBuilder;
+import io.dropwizard.client.JerseyClientConfiguration;
+import io.dropwizard.setup.Environment;
+import org.apache.commons.lang3.StringUtils;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.client.Client;
+
+public class RESTServiceFactory {
+    @JsonProperty
+    private String protocol;
+
+    @JsonProperty
+    private String host;
+
+    @JsonProperty
+    private int port;
+
+    @Valid
+    @NotNull
+    @JsonProperty("jerseyClient")
+    private JerseyClientConfiguration jerseyClientConfiguration;
+
+    public RESTService build(Environment environment, String name) {
+        return build(environment, name, null);
+    }
+
+    public RESTService build(Environment environment, String name, String userAgent) {
+        Client client = new JerseyClientBuilder(environment).using(jerseyClientConfiguration).build(name).register(MultiPartFeature.class);
+        return StringUtils.isNotEmpty(host) ?
+                new RESTService(client, getURL(), userAgent) : new RESTService(client, userAgent);
+    }
+
+    private String getURL() {
+        return String.format("%s://%s:%d", protocol, host, port);
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ApiCallbacks.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ApiCallbacks.java
new file mode 100644
index 0000000..dfbdfb8
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ApiCallbacks.java
@@ -0,0 +1,45 @@
+/*
+ * 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.datalab.rest.contracts;
+
+public class ApiCallbacks {
+    public static final String API = "/api";
+    public static final String KEY_LOADER = API + "/user/access_key/callback";
+    public static final String INFRASTRUCTURE_PROVISION = API + "/infrastructure_provision";
+    public static final String COMPUTATIONAL = INFRASTRUCTURE_PROVISION + "/computational_resources";
+    public static final String EXPLORATORY = INFRASTRUCTURE_PROVISION + "/exploratory_environment";
+    public static final String LIBRARY = INFRASTRUCTURE_PROVISION + "/library";
+    public static final String UPDATE_LIBS_URI = LIBRARY + "/update_lib_list";
+    public static final String INFRASTRUCTURE = API + "/infrastructure";
+    public static final String EDGE = INFRASTRUCTURE + "/edge";
+    public static final String STATUS_URI = "/status";
+    public static final String LIB_STATUS_URI = LIBRARY + "/lib_status";
+    public static final String GIT_CREDS = API + "/user/git_creds" + STATUS_URI;
+    public static final String IMAGE = INFRASTRUCTURE_PROVISION + "/image";
+    public static final String IMAGE_STATUS_URI = IMAGE + "/image_status";
+    public static final String BACKUP_URI = API + "/infrastructure/backup" + STATUS_URI;
+    public static final String REUPLOAD_KEY_URI = API + "/infrastructure/reupload_key/callback";
+    public static final String CHECK_INACTIVITY_EXPLORATORY_URI = API + "/infrastructure/inactivity/callback/exploratory";
+    public static final String CHECK_INACTIVITY_COMPUTATIONAL_URI = API + "/infrastructure/inactivity/callback" +
+            "/computational";
+
+    private ApiCallbacks() {
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/BackupAPI.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/BackupAPI.java
new file mode 100644
index 0000000..4e1642b
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/BackupAPI.java
@@ -0,0 +1,27 @@
+/*
+ * 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.datalab.rest.contracts;
+
+public class BackupAPI {
+    public static final String BACKUP = "backup";
+
+    private BackupAPI() {
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ComputationalAPI.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ComputationalAPI.java
new file mode 100644
index 0000000..c4c2a94
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ComputationalAPI.java
@@ -0,0 +1,41 @@
+/*
+ * 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.datalab.rest.contracts;
+
+public interface ComputationalAPI {
+    String AUDIT_MESSAGE = "Notebook name %s";
+    String AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE = "Reconfigure compute %s, requested for notebook %s";
+    String LIBRARY = "library/";
+    String COMPUTATIONAL = "computational";
+    String COMPUTATIONAL_CREATE = COMPUTATIONAL + "/create";
+    String COMPUTATIONAL_STOP = COMPUTATIONAL + "/stop";
+    String COMPUTATIONAL_START = COMPUTATIONAL + "/start";
+    String SPARK = "/spark";
+    String COMPUTATIONAL_CREATE_SPARK = COMPUTATIONAL_CREATE + SPARK;
+    String COMPUTATIONAL_RECONFIGURE_SPARK = COMPUTATIONAL + SPARK + "/reconfigure";
+    String COMPUTATIONAL_CREATE_CLOUD_SPECIFIC = COMPUTATIONAL_CREATE + "/cloud";
+    String COMPUTATIONAL_TERMINATE = COMPUTATIONAL + "/terminate";
+    String COMPUTATIONAL_TERMINATE_SPARK = COMPUTATIONAL_TERMINATE + SPARK;
+    String COMPUTATIONAL_STOP_SPARK = COMPUTATIONAL_STOP + SPARK;
+    String COMPUTATIONAL_START_SPARK = COMPUTATIONAL_START + SPARK;
+    String COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC = COMPUTATIONAL_TERMINATE + "/cloud";
+    String COMPUTATIONAL_LIB_INSTALL = LIBRARY + COMPUTATIONAL + "/lib_install";
+    String COMPUTATIONAL_LIB_LIST = LIBRARY + COMPUTATIONAL + "/lib_list";
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/DockerAPI.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/DockerAPI.java
new file mode 100644
index 0000000..48aa0ab
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/DockerAPI.java
@@ -0,0 +1,27 @@
+/*
+ * 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.datalab.rest.contracts;
+
+public interface DockerAPI {
+    String DOCKER = "docker";
+    String DOCKER_RUN = DOCKER + "/run";
+    String DOCKER_EXPLORATORY = DOCKER + "/exploratory";
+    String DOCKER_COMPUTATIONAL = DOCKER + "/computational";
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ExploratoryAPI.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ExploratoryAPI.java
new file mode 100644
index 0000000..d153a15
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ExploratoryAPI.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab.rest.contracts;
+
+public interface ExploratoryAPI {
+    String LIBRARY = "library/";
+    String EXPLORATORY = "exploratory";
+    String EXPLORATORY_CREATE = EXPLORATORY + "/create";
+    String EXPLORATORY_RECONFIGURE_SPARK = EXPLORATORY + "/reconfigure_spark";
+    String EXPLORATORY_START = EXPLORATORY + "/start";
+    String EXPLORATORY_TERMINATE = EXPLORATORY + "/terminate";
+    String EXPLORATORY_STOP = EXPLORATORY + "/stop";
+    String EXPLORATORY_LIB_INSTALL = LIBRARY + EXPLORATORY + "/lib_install";
+    String EXPLORATORY_LIB_LIST = LIBRARY + EXPLORATORY + "/lib_list";
+    String EXPLORATORY_GIT_CREDS = EXPLORATORY + "/git_creds";
+    String EXPLORATORY_IMAGE = EXPLORATORY + "/image";
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/InfrasctructureAPI.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/InfrasctructureAPI.java
new file mode 100644
index 0000000..9b1c1f4
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/InfrasctructureAPI.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab.rest.contracts;
+
+public final class InfrasctructureAPI {
+    public static final String INFRASTRUCTURE = "infrastructure";
+    public static final String INFRASTRUCTURE_STATUS = INFRASTRUCTURE + "/status";
+    public static final String EXPLORATORY_CHECK_INACTIVITY = INFRASTRUCTURE + "/exploratory/check_inactivity";
+    public static final String COMPUTATIONAL_CHECK_INACTIVITY = INFRASTRUCTURE + "/computational/check_inactivity";
+
+    private InfrasctructureAPI() {
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/KeyAPI.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/KeyAPI.java
new file mode 100644
index 0000000..613a72e
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/KeyAPI.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab.rest.contracts;
+
+public class KeyAPI {
+    public static final String REUPLOAD_KEY = "/key/reupload";
+    public static final String GET_ADMIN_KEY = "key";
+    public static final String KEY_EXTENTION = ".pub";
+
+    private KeyAPI() {
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/dto/ErrorDTO.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/dto/ErrorDTO.java
new file mode 100644
index 0000000..1d1c148
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/dto/ErrorDTO.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.rest.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ErrorDTO {
+
+    @JsonProperty
+    private final int code;
+    @JsonProperty
+    private final String message;
+
+    public ErrorDTO(int code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/AuthenticationExceptionMapper.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/AuthenticationExceptionMapper.java
new file mode 100644
index 0000000..ac37e3d
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/AuthenticationExceptionMapper.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.rest.mappers;
+
+import com.epam.datalab.exceptions.DatalabAuthenticationException;
+import com.epam.datalab.rest.dto.ErrorDTO;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+public class AuthenticationExceptionMapper implements ExceptionMapper<DatalabAuthenticationException> {
+    @Override
+    public Response toResponse(DatalabAuthenticationException exception) {
+        final Response.Status unauthorized = Response.Status.UNAUTHORIZED;
+        return Response.status(unauthorized)
+                .entity(new ErrorDTO(unauthorized.getStatusCode(), exception.getMessage()))
+                .type(MediaType.APPLICATION_JSON)
+                .build();
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/DatalabValidationExceptionMapper.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/DatalabValidationExceptionMapper.java
new file mode 100644
index 0000000..6abf825
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/DatalabValidationExceptionMapper.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.rest.mappers;
+
+import com.epam.datalab.exceptions.DatalabValidationException;
+import com.epam.datalab.rest.dto.ErrorDTO;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+public class DatalabValidationExceptionMapper implements ExceptionMapper<DatalabValidationException> {
+    @Override
+    public Response toResponse(DatalabValidationException exception) {
+        final Response.Status badRequest = Response.Status.BAD_REQUEST;
+        return Response.status(badRequest)
+                .entity(new ErrorDTO(badRequest.getStatusCode(), exception.getMessage()))
+                .type(MediaType.APPLICATION_JSON)
+                .build();
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/GenericExceptionMapper.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/GenericExceptionMapper.java
new file mode 100644
index 0000000..6c97897
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/GenericExceptionMapper.java
@@ -0,0 +1,43 @@
+/*
+ * 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.datalab.rest.mappers;
+
+import com.epam.datalab.rest.dto.ErrorDTO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+public abstract class GenericExceptionMapper<E extends Exception> implements ExceptionMapper<E> {
+    static final Logger LOGGER = LoggerFactory.getLogger(GenericExceptionMapper.class);
+
+    @Override
+    public Response toResponse(E exception) {
+        LOGGER.error("Uncaught exception in application", exception);
+
+        return Response
+                .serverError()
+                .entity(new ErrorDTO(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), exception.getMessage()))
+                .type(MediaType.APPLICATION_JSON)
+                .build();
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/JsonProcessingExceptionMapper.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/JsonProcessingExceptionMapper.java
new file mode 100644
index 0000000..e19077d
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/JsonProcessingExceptionMapper.java
@@ -0,0 +1,28 @@
+/*
+ * 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.datalab.rest.mappers;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+import javax.ws.rs.ext.Provider;
+
+@Provider
+public class JsonProcessingExceptionMapper extends GenericExceptionMapper<JsonProcessingException> {
+}
\ No newline at end of file
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/ResourceConflictExceptionMapper.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/ResourceConflictExceptionMapper.java
new file mode 100644
index 0000000..2ab40b5
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/ResourceConflictExceptionMapper.java
@@ -0,0 +1,40 @@
+/*
+ * 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.datalab.rest.mappers;
+
+import com.epam.datalab.exceptions.ResourceConflictException;
+import com.epam.datalab.rest.dto.ErrorDTO;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+public class ResourceConflictExceptionMapper implements ExceptionMapper<ResourceConflictException> {
+    @Override
+    public Response toResponse(ResourceConflictException e) {
+        final Response.Status conflict = Response.Status.CONFLICT;
+        return Response.status(conflict)
+                .type(MediaType.APPLICATION_JSON)
+                .entity(new ErrorDTO(conflict.getStatusCode(), e.getMessage()))
+                .build();
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/ResourceNotFoundExceptionMapper.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/ResourceNotFoundExceptionMapper.java
new file mode 100644
index 0000000..adcd174
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/ResourceNotFoundExceptionMapper.java
@@ -0,0 +1,40 @@
+/*
+ * 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.datalab.rest.mappers;
+
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.rest.dto.ErrorDTO;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+public class ResourceNotFoundExceptionMapper implements ExceptionMapper<ResourceNotFoundException> {
+    @Override
+    public Response toResponse(ResourceNotFoundException e) {
+        final Response.Status notFound = Response.Status.NOT_FOUND;
+        return Response.status(notFound)
+                .type(MediaType.APPLICATION_JSON)
+                .entity(new ErrorDTO(notFound.getStatusCode(), e.getMessage()))
+                .build();
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/ResourceQuoteReachedExceptionMapper.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/ResourceQuoteReachedExceptionMapper.java
new file mode 100644
index 0000000..821a77d
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/ResourceQuoteReachedExceptionMapper.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab.rest.mappers;
+
+import com.epam.datalab.exceptions.ResourceQuoteReachedException;
+import com.epam.datalab.rest.dto.ErrorDTO;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+public class ResourceQuoteReachedExceptionMapper implements ExceptionMapper<ResourceQuoteReachedException> {
+    @Override
+    public Response toResponse(ResourceQuoteReachedException exception) {
+        final Response.Status forbidden = Response.Status.FORBIDDEN;
+        return Response.status(forbidden)
+                .type(MediaType.APPLICATION_JSON_TYPE)
+                .entity(new ErrorDTO(forbidden.getStatusCode(), exception.getMessage()))
+                .build();
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/RuntimeExceptionMapper.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/RuntimeExceptionMapper.java
new file mode 100644
index 0000000..918729a
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/RuntimeExceptionMapper.java
@@ -0,0 +1,63 @@
+/*
+ * 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.datalab.rest.mappers;
+
+import com.epam.datalab.rest.dto.ErrorDTO;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+@Slf4j
+public class RuntimeExceptionMapper extends GenericExceptionMapper<RuntimeException> {
+
+    @Override
+    public Response toResponse(RuntimeException exception) {
+        if (exception instanceof WebApplicationException) {
+            return handleWebApplicationException(exception);
+        }
+        return super.toResponse(exception);
+    }
+
+    private Response handleWebApplicationException(RuntimeException exception) {
+        WebApplicationException webAppException = (WebApplicationException) exception;
+
+        if (webAppException.getResponse().getStatusInfo() == Response.Status.UNAUTHORIZED
+                || webAppException.getResponse().getStatusInfo() == Response.Status.FORBIDDEN) {
+
+            return web(exception, Response.Status.UNAUTHORIZED);
+        } else if (webAppException.getResponse().getStatusInfo() == Response.Status.NOT_FOUND) {
+            return web(exception, Response.Status.NOT_FOUND);
+        }
+
+        return super.toResponse(exception);
+    }
+
+    private Response web(RuntimeException exception, Response.StatusType status) {
+        log.error("Web application exception: {}", exception.getMessage(), exception);
+        return Response.status(status)
+                .type(MediaType.APPLICATION_JSON)
+                .entity(new ErrorDTO(status.getStatusCode(), exception.getMessage()))
+                .build();
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/ValidationExceptionMapper.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/ValidationExceptionMapper.java
new file mode 100644
index 0000000..f89b10c
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/mappers/ValidationExceptionMapper.java
@@ -0,0 +1,45 @@
+/*
+ * 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.datalab.rest.mappers;
+
+import com.epam.datalab.rest.dto.ErrorDTO;
+import io.dropwizard.jersey.validation.ConstraintMessage;
+import io.dropwizard.jersey.validation.JerseyViolationException;
+import org.glassfish.jersey.server.model.Invocable;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import java.util.stream.Collectors;
+
+public class ValidationExceptionMapper implements ExceptionMapper<JerseyViolationException> {
+    @Override
+    public Response toResponse(JerseyViolationException exception) {
+        Invocable invocable = exception.getInvocable();
+        final String errors =
+                exception.getConstraintViolations()
+                        .stream().map(violation -> ConstraintMessage.getMessage(violation, invocable))
+                        .collect(Collectors.joining(","));
+        return Response.status(Response.Status.BAD_REQUEST)
+                .entity(new ErrorDTO(Response.Status.BAD_REQUEST.getStatusCode(), errors))
+                .type(MediaType.APPLICATION_JSON)
+                .build();
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/validation/AwsValidation.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/validation/AwsValidation.java
new file mode 100644
index 0000000..ba91b30
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/validation/AwsValidation.java
@@ -0,0 +1,23 @@
+/*
+ * 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.datalab.validation;
+
+public interface AwsValidation {
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/validation/AzureValidation.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/validation/AzureValidation.java
new file mode 100644
index 0000000..e0dfd6d
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/validation/AzureValidation.java
@@ -0,0 +1,23 @@
+/*
+ * 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.datalab.validation;
+
+public interface AzureValidation {
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/validation/CloudConfigurationSequenceProvider.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/validation/CloudConfigurationSequenceProvider.java
new file mode 100644
index 0000000..e1045c4
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/validation/CloudConfigurationSequenceProvider.java
@@ -0,0 +1,66 @@
+/*
+ * 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.datalab.validation;
+
+import com.epam.datalab.ServiceConfiguration;
+import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;
+
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CloudConfigurationSequenceProvider<T extends ServiceConfiguration> implements DefaultGroupSequenceProvider<T> {
+    @Override
+    public List<Class<?>> getValidationGroups(T c) {
+        List<Class<?>> sequence = new ArrayList<>();
+
+        sequence.add(initialSequenceGroup());
+
+        if (c == null) {
+            return sequence;
+        } else {
+            switch (c.getCloudProvider()) {
+                case AWS:
+                    sequence.add(AwsValidation.class);
+                    break;
+                case AZURE:
+                    sequence.add(AzureValidation.class);
+                    break;
+                case GCP:
+                    sequence.add(GcpValidation.class);
+                    break;
+                default:
+                    throw new IllegalArgumentException("Cloud provider is not supported" + c.getCloudProvider());
+            }
+        }
+
+        return sequence;
+    }
+
+    private Class<T> initialSequenceGroup() {
+        ParameterizedType parameterizedType = (ParameterizedType) getClass()
+                .getGenericSuperclass();
+
+        @SuppressWarnings("unchecked")
+        Class<T> ret = (Class<T>) parameterizedType.getActualTypeArguments()[0];
+
+        return ret;
+    }
+}
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/validation/GcpValidation.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/validation/GcpValidation.java
new file mode 100644
index 0000000..6dc70d5
--- /dev/null
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/validation/GcpValidation.java
@@ -0,0 +1,23 @@
+/*
+ * 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.datalab.validation;
+
+public interface GcpValidation {
+}
diff --git a/services/dlab-model/pom.xml b/services/dlab-model/pom.xml
deleted file mode 100644
index 17e5b31..0000000
--- a/services/dlab-model/pom.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ 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.
-  -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <artifactId>dlab</artifactId>
-        <groupId>com.epam.dlab</groupId>
-        <version>1.0</version>
-        <relativePath>../../pom.xml</relativePath>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>dlab-model</artifactId>
-
-    <dependencies>
-        <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>common</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>dlab-utils</artifactId>
-            <version>${project.parent.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>javax.ws.rs</groupId>
-            <artifactId>javax.ws.rs-api</artifactId>
-            <version>2.0</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>javax.validation</groupId>
-            <artifactId>validation-api</artifactId>
-            <version>2.0.0.Final</version>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-lang3</artifactId>
-            <version>3.7</version>
-            <scope>provided</scope>
-        </dependency>
-
-        <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
-        <dependency>
-            <groupId>org.hibernate</groupId>
-            <artifactId>hibernate-validator</artifactId>
-            <version>${hibernate.validator.version}</version>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>io.dropwizard</groupId>
-            <artifactId>dropwizard-jackson</artifactId>
-            <scope>provided</scope>
-        </dependency>
-
-    </dependencies>
-
-</project>
\ No newline at end of file
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/MongoKeyWords.java b/services/dlab-model/src/main/java/com/epam/dlab/MongoKeyWords.java
deleted file mode 100644
index 1ba4eed..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/MongoKeyWords.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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;
-
-public abstract class MongoKeyWords {
-    public static final String AZURE_BILLING_SCHEDULER = "billingScheduler";
-    public static final String AZURE_BILLING_SCHEDULER_HISTORY = "billingSchedulerHistory";
-
-    /**
-     * Mongo DB keywords related to billing functionality
-     */
-    public static final String MONGO_ID = "_id";
-
-
-    private MongoKeyWords() {
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/InfrastructureMetaInfoDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/InfrastructureMetaInfoDTO.java
deleted file mode 100644
index 6c3b603..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/InfrastructureMetaInfoDTO.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Data;
-
-@Data
-@Builder
-public class InfrastructureMetaInfoDTO {
-	private final String branch;
-	private final String version;
-	private final String commit;
-	@JsonProperty("release_notes")
-	private final String releaseNotes;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/LibListComputationalDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/LibListComputationalDTO.java
deleted file mode 100644
index df92c54..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/LibListComputationalDTO.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.dto;
-
-import com.epam.dlab.dto.exploratory.ExploratoryActionDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-@Getter
-@Setter
-@ToString(callSuper = true)
-public class LibListComputationalDTO extends ExploratoryActionDTO<LibListComputationalDTO> {
-    @JsonProperty("computational_id")
-    private String computationalId;
-
-    @JsonProperty("computational_image")
-    private String computationalImage;
-
-    @JsonProperty
-    private String libCacheKey;
-
-    public LibListComputationalDTO withComputationalId(String computationalId) {
-        setComputationalId(computationalId);
-        return this;
-    }
-
-    public LibListComputationalDTO withComputationalImage(String computationalImage) {
-        setComputationalImage(computationalImage);
-        return this;
-    }
-
-    public LibListComputationalDTO withLibCacheKey(String libCacheKey) {
-        setLibCacheKey(libCacheKey);
-        return this;
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/LibListExploratoryDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/LibListExploratoryDTO.java
deleted file mode 100644
index a4487b7..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/LibListExploratoryDTO.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.dto;
-
-import com.epam.dlab.dto.exploratory.ExploratoryActionDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-@Getter
-@Setter
-@ToString(callSuper = true)
-public class LibListExploratoryDTO extends ExploratoryActionDTO<LibListExploratoryDTO> {
-
-	@JsonProperty
-	private String libCacheKey;
-
-	public LibListExploratoryDTO withLibCacheKey(String libCacheKey) {
-		setLibCacheKey(libCacheKey);
-		return this;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/LibraryGroups.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/LibraryGroups.java
deleted file mode 100644
index f6c5d93..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/LibraryGroups.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.dto;
-
-public enum LibraryGroups {
-	GROUP_JAVA("java"),
-	GROUP_PIP2("pip2"),
-	GROUP_PIP3("pip3"),
-	GROUP_R_PKG("r_pkg"),
-	GROUP_OS_PKG("os_pkg"),
-	GROUP_OTHERS("others");
-
-	private String name;
-
-	LibraryGroups(String name) {
-		this.name = name;
-	}
-
-	@Override
-	public String toString() {
-		return name;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/ResourceBaseDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/ResourceBaseDTO.java
deleted file mode 100644
index de34af9..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/ResourceBaseDTO.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.dto;
-
-import com.epam.dlab.dto.base.CloudSettings;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@class")
-public abstract class ResourceBaseDTO<T extends ResourceBaseDTO<?>> {
-	@SuppressWarnings("unchecked")
-	private final T self = (T) this;
-	@JsonProperty("edge_user_name")
-	private String edgeUserName;
-	@JsonProperty
-	private CloudSettings cloudSettings;
-
-	public String getEdgeUserName() {
-		return edgeUserName;
-	}
-
-	public void setEdgeUserName(String edgeUserName) {
-		this.edgeUserName = edgeUserName;
-	}
-
-	public T withEdgeUserName(String edgeUserName) {
-		setEdgeUserName(edgeUserName);
-		return self;
-	}
-
-	public CloudSettings getCloudSettings() {
-		return cloudSettings;
-	}
-
-	public void setCloudSettings(CloudSettings cloudSettings) {
-		this.cloudSettings = cloudSettings;
-	}
-
-	public T withCloudSettings(CloudSettings cloudSettings) {
-		setCloudSettings(cloudSettings);
-		return self;
-	}
-
-	public ToStringHelper toStringHelper(Object self) {
-		return MoreObjects.toStringHelper(self)
-				.add("edgeUserName", edgeUserName)
-				.add("cloudSettings", cloudSettings);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/ResourceEnvBaseDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/ResourceEnvBaseDTO.java
deleted file mode 100644
index 045cf12..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/ResourceEnvBaseDTO.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-public class ResourceEnvBaseDTO<T extends ResourceEnvBaseDTO<?>> extends ResourceSysBaseDTO<T> {
-    @JsonProperty("exploratory_name")
-    private String exploratoryName;
-    @JsonProperty("application")
-    private String applicationName;
-
-    @SuppressWarnings("unchecked")
-	private final T self = (T)this;
-
-    public String getExploratoryName() {
-        return exploratoryName;
-    }
-
-    public void setExploratoryName(String exploratoryName) {
-        this.exploratoryName = exploratoryName;
-    }
-
-    public T withExploratoryName(String exploratoryName) {
-        setExploratoryName(exploratoryName);
-        return self;
-    }
-
-    public String getApplicationName() {
-        return applicationName;
-    }
-
-    public void setApplicationName(String applicationName) {
-        this.applicationName = applicationName;
-    }
-
-    public T withApplicationName(String applicationName) {
-        setApplicationName(applicationName);
-        return self;
-    }
-    
-    @Override
-    public ToStringHelper toStringHelper(Object self) {
-    	return super.toStringHelper(self)
-    	        .add("applicationName", applicationName)
-    	        .add("exploratoryName", exploratoryName);
-    }
-    
-    @Override
-    public String toString() {
-    	return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/ResourceSysBaseDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/ResourceSysBaseDTO.java
deleted file mode 100644
index 8ed3822..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/ResourceSysBaseDTO.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-public class ResourceSysBaseDTO<T extends ResourceSysBaseDTO<?>> extends ResourceBaseDTO<T> {
-    @SuppressWarnings("unchecked")
-    private final T self = (T) this;
-    @JsonProperty("conf_service_base_name")
-    private String serviceBaseName;
-    @JsonProperty("conf_os_family")
-    private String confOsFamily;
-    @JsonProperty("conf_key_dir")
-    private String confKeyDir;
-
-	public String getServiceBaseName() {
-        return serviceBaseName;
-    }
-
-    public void setServiceBaseName(String serviceBaseName) {
-        this.serviceBaseName = serviceBaseName;
-    }
-
-    public T withServiceBaseName(String serviceBaseName) {
-        setServiceBaseName(serviceBaseName);
-        return self;
-    }
-
-    public String getConfOsFamily() {
-        return confOsFamily;
-    }
-
-    public void setConfOsFamily(String confOsFamily) {
-        this.confOsFamily = confOsFamily;
-    }
-
-    public T withConfOsFamily(String confOsFamily) {
-        setConfOsFamily(confOsFamily);
-        return self;
-    }
-
-
-    public String getConfKeyDir() {
-        return confKeyDir;
-    }
-
-    public void setConfKeyDir(String confKeyDir) {
-        this.confKeyDir = confKeyDir;
-    }
-
-    public T withConfKeyDir(String confKeyDir) {
-        setConfKeyDir(confKeyDir);
-        return self;
-    }
-
-    @Override
-    public ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("serviceBaseName", serviceBaseName)
-                .add("confKeyDir", confKeyDir)
-                .add("confOsFamily", confOsFamily);
-    }
-
-    @Override
-    public String toString() {
-        return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/ResourceURL.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/ResourceURL.java
deleted file mode 100644
index fac4891..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/ResourceURL.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-/**
- * Describe URL of resource.
- */
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class ResourceURL {
-	@JsonProperty("description")
-	private String description;
-	@JsonProperty("url")
-	private String url;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/SchedulerJobDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/SchedulerJobDTO.java
deleted file mode 100644
index 8e15a59..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/SchedulerJobDTO.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.time.*;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Stores info about a scheduler job (general duration, days to repeat, time to start and finish).
- */
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class SchedulerJobDTO {
-
-	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
-	@JsonProperty("begin_date")
-	private LocalDate beginDate;
-
-	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
-	@JsonProperty("finish_date")
-	private LocalDate finishDate;
-
-	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm")
-	@JsonProperty("start_time")
-	private LocalTime startTime;
-
-	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm")
-	@JsonProperty("end_time")
-	private LocalTime endTime;
-
-	@JsonProperty("start_days_repeat")
-	private List<DayOfWeek> startDaysRepeat = Collections.emptyList();
-
-	@JsonProperty("stop_days_repeat")
-	private List<DayOfWeek> stopDaysRepeat = Collections.emptyList();
-
-	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm")
-	@JsonProperty("terminate_datetime")
-	private LocalDateTime terminateDateTime;
-
-	@JsonProperty("timezone_offset")
-	private ZoneOffset timeZoneOffset;
-
-	@JsonProperty("sync_start_required")
-	private boolean syncStartRequired = true;
-
-	@JsonProperty("max_inactivity")
-	private Long maxInactivity;
-	@JsonProperty("check_inactivity_required")
-	private boolean checkInactivityRequired;
-	@JsonProperty("consider_inactivity")
-	private boolean considerInactivity = true;
-
-	public boolean inactivityScheduler() {
-		return Objects.nonNull(maxInactivity);
-	}
-
-}
\ No newline at end of file
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/StatusBaseDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/StatusBaseDTO.java
deleted file mode 100644
index 14dc5ce..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/StatusBaseDTO.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import java.util.Date;
-
-public abstract class StatusBaseDTO<T extends StatusBaseDTO<?>> {
-	@JsonProperty("request_id")
-	private String requestId;
-	@JsonProperty
-	private String user;
-	@JsonProperty
-	private String status;
-	@JsonProperty("error_message")
-	private String errorMessage;
-	@JsonProperty("up_time")
-	private Date uptime;
-
-	@SuppressWarnings("unchecked")
-	private final T self = (T) this;
-
-	public String getRequestId() {
-		return requestId;
-	}
-
-	public void setRequestId(String requestId) {
-		this.requestId = requestId;
-	}
-
-	public T withRequestId(String requestId) {
-		setRequestId(requestId);
-		return self;
-	}
-
-	public String getUser() {
-		return user;
-	}
-
-	public void setUser(String user) {
-		this.user = user;
-	}
-
-	public T withUser(String user) {
-		setUser(user);
-		return self;
-	}
-
-	public String getStatus() {
-		return status;
-	}
-
-	public void setStatus(String status) {
-		this.status = status;
-	}
-
-	public T withStatus(String status) {
-		setStatus(status);
-		return self;
-	}
-
-	public T withStatus(UserInstanceStatus status) {
-		return withStatus(status.toString());
-	}
-
-	public String getErrorMessage() {
-		return errorMessage;
-	}
-
-	public void setErrorMessage(String errorMessage) {
-		this.errorMessage = errorMessage;
-	}
-
-	public T withErrorMessage(String errorMessage) {
-		setErrorMessage(errorMessage);
-		return self;
-	}
-
-	public Date getUptime() {
-		return uptime;
-	}
-
-	public void setUptime(Date uptime) {
-		this.uptime = uptime;
-	}
-
-	@SuppressWarnings("unchecked")
-	public T withUptime(Date uptime) {
-		setUptime(uptime);
-		return (T) this;
-	}
-
-	public ToStringHelper toStringHelper(Object self) {
-		return MoreObjects.toStringHelper(self)
-				.add("requestId", requestId)
-				.add("user", user)
-				.add("status", status)
-				.add("errorMessage", errorMessage)
-				.add("uptime", uptime);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/StatusEnvBaseDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/StatusEnvBaseDTO.java
deleted file mode 100644
index 16d36be..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/StatusEnvBaseDTO.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-public abstract class StatusEnvBaseDTO<T extends StatusEnvBaseDTO<?>> extends StatusBaseDTO<T> {
-    @SuppressWarnings("unchecked")
-    private final T self = (T) this;
-    @JsonProperty("instance_id")
-    private String instanceId;
-    @JsonProperty("exploratory_name")
-    private String exploratoryName;
-    private String project;
-    @JsonProperty("exploratory_id")
-    private String exploratoryId;
-    @JsonProperty("exploratory_template_name")
-    private String exploratoryTemplateName;
-
-    public String getInstanceId() {
-        return instanceId;
-    }
-
-    private void setInstanceId(String instanceId) {
-        this.instanceId = instanceId;
-    }
-
-    public T withInstanceId(String instanceId) {
-        setInstanceId(instanceId);
-        return self;
-    }
-
-    public String getExploratoryName() {
-        return exploratoryName;
-    }
-
-    public void setExploratoryName(String exploratoryName) {
-        this.exploratoryName = exploratoryName;
-    }
-
-    public T withExploratoryName(String exploratoryName) {
-        setExploratoryName(exploratoryName);
-        return self;
-    }
-
-    public String getProject() {
-        return project;
-    }
-
-    public void setProject(String project) {
-        this.project = project;
-    }
-
-    public T withProject(String project) {
-        setProject(project);
-        return self;
-    }
-
-    public String getExploratoryId() {
-        return exploratoryId;
-    }
-
-    public void setExploratoryId(String exploratoryId) {
-        this.exploratoryId = exploratoryId;
-    }
-
-    public T withExploratoryId(String exploratoryId) {
-        setExploratoryId(exploratoryId);
-        return self;
-    }
-
-    public String getExploratoryTemplateName() {
-        return exploratoryTemplateName;
-    }
-
-    private void setExploratoryTemplateName(String exploratoryTemplateName) {
-        this.exploratoryTemplateName = exploratoryTemplateName;
-    }
-
-    public T withExploratoryTemplateName(String exploratoryTemplateName) {
-        setExploratoryTemplateName(exploratoryTemplateName);
-        return self;
-    }
-
-    @Override
-    public ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("instanceId", instanceId)
-                .add("exploratoryName", exploratoryName)
-                .add("exploratoryId", exploratoryId)
-                .add("exploratoryTemplateName", exploratoryTemplateName);
-    }
-
-    @Override
-    public String toString() {
-        return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/UserEnvironmentResources.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/UserEnvironmentResources.java
deleted file mode 100644
index d563d14..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/UserEnvironmentResources.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.dto;
-
-import com.epam.dlab.dto.status.EnvResourceList;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-public class UserEnvironmentResources extends ResourceSysBaseDTO<UserEnvironmentResources> {
-    @JsonProperty("edge_list_resources")
-    private EnvResourceList resourceList;
-
-    /**
-     * Return the list of resources (hosts, clusters, storages).
-     */
-    public EnvResourceList getResourceList() {
-        return resourceList;
-    }
-
-    /**
-     * Set the list of resources (hosts, clusters, storages).
-     */
-    public void setResourceList(EnvResourceList resourceList) {
-        this.resourceList = resourceList;
-    }
-
-    /**
-     * Set the list of resources (hosts, clusters, storages).
-     */
-    public UserEnvironmentResources withResourceList(EnvResourceList resourceList) {
-        setResourceList(resourceList);
-        return this;
-    }
-
-    @Override
-    public ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("resourceList", resourceList);
-    }
-
-    @Override
-    public String toString() {
-        return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/UserInstanceDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/UserInstanceDTO.java
deleted file mode 100644
index 1950312..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/UserInstanceDTO.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * 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.dto;
-
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.dto.exploratory.LibInstallDTO;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Stores info about the user notebook.
- */
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class UserInstanceDTO {
-	@JsonProperty("_id")
-	private String id;
-	@JsonProperty
-	private String user;
-	@JsonProperty("exploratory_name")
-	private String exploratoryName;
-	@JsonProperty("exploratory_id")
-	private String exploratoryId;
-	@JsonProperty("image")
-	private String imageName;
-	@JsonProperty("version")
-	private String imageVersion;
-	@JsonProperty("project")
-	private String project;
-	@JsonProperty("endpoint")
-	private String endpoint;
-	@JsonProperty("cloud_provider")
-	private String cloudProvider;
-	@JsonProperty("template_name")
-	private String templateName;
-	@JsonProperty
-	private String status;
-	@JsonProperty
-	private String shape;
-	@JsonProperty("exploratory_url")
-	private List<ResourceURL> resourceUrl;
-	@JsonProperty("up_time")
-	private Date uptime;
-	@JsonProperty("computational_resources")
-	private List<UserComputationalResource> resources = new ArrayList<>();
-	@JsonProperty("private_ip")
-	private String privateIp;
-	@JsonProperty("scheduler_data")
-	private SchedulerJobDTO schedulerData;
-	@JsonProperty("reupload_key_required")
-	private boolean reuploadKeyRequired = false;
-	@JsonInclude(JsonInclude.Include.NON_EMPTY)
-	private List<LibInstallDTO> libs = Collections.emptyList();
-	@JsonProperty("last_activity")
-	private LocalDateTime lastActivity;
-	@JsonProperty("cluster_config")
-	private List<ClusterConfig> clusterConfig;
-	@JsonProperty
-	private Map<String, String> tags;
-
-	/**
-	 * Sets the user login name.
-	 */
-	public UserInstanceDTO withUser(String user) {
-		setUser(user);
-		return this;
-	}
-
-	/**
-	 * Sets the name of exploratory.
-	 */
-	public UserInstanceDTO withExploratoryName(String exploratoryName) {
-		setExploratoryName(exploratoryName);
-		return this;
-	}
-
-	/**
-	 * Sets the exploratory id.
-	 */
-	public UserInstanceDTO withExploratoryId(String exploratoryId) {
-		setExploratoryId(exploratoryId);
-		return this;
-	}
-
-	/**
-	 * Sets the image name.
-	 */
-	public UserInstanceDTO withImageName(String imageName) {
-		setImageName(imageName);
-		return this;
-	}
-
-	public UserInstanceDTO withClusterConfig(List<ClusterConfig> config) {
-		setClusterConfig(config);
-		return this;
-	}
-
-	/**
-	 * Sets the image version.
-	 */
-	public UserInstanceDTO withImageVersion(String imageVersion) {
-		setImageVersion(imageVersion);
-		return this;
-	}
-
-	/**
-	 * Sets the name of template.
-	 */
-	public UserInstanceDTO withTemplateName(String templateName) {
-		setTemplateName(templateName);
-		return this;
-	}
-
-	/**
-	 * Sets the status of notebook.
-	 */
-	public UserInstanceDTO withStatus(String status) {
-		setStatus(status);
-		return this;
-	}
-
-	/**
-	 * Sets the name of notebook shape.
-	 */
-	public UserInstanceDTO withShape(String shape) {
-		setShape(shape);
-		return this;
-	}
-
-	public UserInstanceDTO withProject(String project) {
-		setProject(project);
-		return this;
-	}
-
-	/**
-	 * Sets a list of user's computational resources for notebook.
-	 */
-	public UserInstanceDTO withResources(List<UserComputationalResource> resources) {
-		setResources(resources);
-		return this;
-	}
-
-	/**
-	 * Sets library list.
-	 */
-	public UserInstanceDTO withLibs(List<LibInstallDTO> libs) {
-		setLibs(libs);
-		return this;
-	}
-
-	public UserInstanceDTO withEndpoint(String endpoint) {
-		setEndpoint(endpoint);
-		return this;
-	}
-
-	public UserInstanceDTO withCloudProvider(String cloudProvider) {
-		setCloudProvider(cloudProvider);
-		return this;
-	}
-
-	public UserInstanceDTO withTags(Map<String, String> tags) {
-		setTags(tags);
-		return this;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/UserInstanceStatus.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/UserInstanceStatus.java
deleted file mode 100644
index 463a61b..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/UserInstanceStatus.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.dto;
-
-public enum UserInstanceStatus {
-	CREATING("creating"),
-	CREATED("created"),
-	STARTING("starting"),
-	CONFIGURING("configuring"),
-	RUNNING("running"),
-	STOPPING("stopping"),
-	STOPPED("stopped"),
-	TERMINATING("terminating"),
-	TERMINATED("terminated"),
-	FAILED("failed"),
-	CREATING_IMAGE("creating image"),
-	RECONFIGURING("reconfiguring"),
-	REUPLOADING_KEY("reuploading key");
-
-	private String name;
-
-	UserInstanceStatus(String name) {
-		this.name = name;
-	}
-
-	@Override
-	public String toString() {
-		return name;
-	}
-
-	public static UserInstanceStatus of(String status) {
-		if (status != null) {
-			for (UserInstanceStatus uis : UserInstanceStatus.values()) {
-				if (status.equalsIgnoreCase(uis.toString())) {
-					return uis;
-				}
-			}
-		}
-		return null;
-	}
-
-	public boolean in(UserInstanceStatus... statusList) {
-		for (UserInstanceStatus status : statusList) {
-			if (this.equals(status)) {
-				return true;
-			}
-		}
-		return false;
-	}
-}
\ No newline at end of file
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/AwsCloudSettings.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/AwsCloudSettings.java
deleted file mode 100644
index 1903f30..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/AwsCloudSettings.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.dto.aws;
-
-import com.epam.dlab.dto.base.CloudSettings;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.*;
-
-@Data
-@ToString(callSuper = true)
-@EqualsAndHashCode(callSuper = true)
-@NoArgsConstructor
-@AllArgsConstructor
-@Builder
-public class AwsCloudSettings extends CloudSettings {
-
-	@JsonProperty("aws_iam_user")
-	private String awsIamUser;
-	@JsonProperty("aws_region")
-	private String awsRegion;
-	@JsonProperty("aws_subnet_id")
-	private String awsSubnetId;
-	@JsonProperty("aws_security_groups_ids")
-	private String awsSecurityGroupIds;
-	@JsonProperty("aws_vpc_id")
-	private String awsVpcId;
-	@JsonProperty("conf_tag_resource_id")
-	private String confTagResourceId;
-	@JsonProperty("aws_notebook_subnet_id")
-	private String awsNotebookSubnetId;
-	@JsonProperty("aws_notebook_vpc_id")
-	private String awsNotebookVpcId;
-	@JsonProperty("aws_zone")
-	private String zone;
-	@JsonProperty("ldap_hostname")
-	protected String ldapHost;
-	@JsonProperty("ldap_dn")
-	protected String ldapDn;
-	@JsonProperty("ldap_ou")
-	protected String ldapOu;
-	@JsonProperty("ldap_service_username")
-	protected String ldapUser;
-	@JsonProperty("ldap_service_password")
-	protected String ldapPassword;
-	@JsonProperty("conf_os_family")
-	protected String os;
-	@JsonProperty("conf_cloud_provider")
-	protected String cloud;
-	@JsonProperty("conf_service_base_name")
-	protected String sbn;
-	@JsonProperty("conf_key_dir")
-	protected String confKeyDir;
-	@JsonProperty("conf_image_enabled")
-	private String imageEnabled;
-	@JsonProperty("conf_stepcerts_enabled")
-	private String stepCertsEnabled;
-	@JsonProperty("conf_stepcerts_root_ca")
-	private String stepCertsRootCA;
-	@JsonProperty("conf_stepcerts_kid")
-	private String stepCertsKid;
-	@JsonProperty("conf_stepcerts_kid_password")
-	private String stepCertsKidPassword;
-	@JsonProperty("conf_stepcerts_ca_url")
-	private String stepCertsCAURL;
-	@JsonProperty("keycloak_auth_server_url")
-	private String keycloakAuthServerUrl;
-	@JsonProperty("keycloak_realm_name")
-	private String keycloakRealmName;
-	@JsonProperty("keycloak_user")
-	private String keycloakUser;
-	@JsonProperty("keycloak_user_password")
-	private String keycloakUserPassword;
-
-	@Override
-	@JsonIgnore
-	public String getIamUser() {
-		return awsIamUser;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/AwsComputationalResource.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/AwsComputationalResource.java
deleted file mode 100644
index 6d4d088..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/AwsComputationalResource.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.dto.aws.computational;
-
-import com.epam.dlab.dto.ResourceURL;
-import com.epam.dlab.dto.SchedulerJobDTO;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.ToString;
-
-import java.time.LocalDateTime;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Stores info about the user's computational resources for notebook.
- */
-@ToString(callSuper = true)
-@Getter
-@EqualsAndHashCode(callSuper = true)
-public class AwsComputationalResource extends UserComputationalResource {
-
-	@JsonProperty("instance_id")
-	private String instanceId;
-	@JsonProperty("master_node_shape")
-	private String masterShape;
-	@JsonProperty("slave_node_shape")
-	private String slaveShape;
-	@JsonProperty("slave_node_spot")
-	private Boolean slaveSpot;
-	@JsonProperty("slave_node_spot_pct_price")
-	private Integer slaveSpotPctPrice;
-	@JsonProperty("total_instance_number")
-	private String slaveNumber;
-	@JsonProperty("emr_version")
-	private String version;
-
-	@Builder
-	public AwsComputationalResource(String computationalName, String computationalId, String imageName,
-									String templateName, String status, Date uptime,
-									SchedulerJobDTO schedulerJobData, boolean reuploadKeyRequired,
-									String instanceId, String masterShape, String slaveShape, Boolean slaveSpot,
-									Integer slaveSpotPctPrice, String slaveNumber, String version,
-									List<ResourceURL> resourceURL, LocalDateTime lastActivity,
-									List<ClusterConfig> config, Map<String, String> tags, int totalInstanceCount) {
-		super(computationalName, computationalId, imageName, templateName, status, uptime, schedulerJobData,
-				reuploadKeyRequired, resourceURL, lastActivity, tags, totalInstanceCount);
-		this.instanceId = instanceId;
-		this.masterShape = masterShape;
-		this.slaveShape = slaveShape;
-		this.slaveSpot = slaveSpot;
-		this.slaveSpotPctPrice = slaveSpotPctPrice;
-		this.slaveNumber = slaveNumber;
-		this.version = version;
-		this.config = config;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/AwsComputationalTerminateDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/AwsComputationalTerminateDTO.java
deleted file mode 100644
index 2775f68..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/AwsComputationalTerminateDTO.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.dto.aws.computational;
-
-import com.epam.dlab.dto.computational.ComputationalTerminateDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.ToString;
-
-@Data
-@ToString(callSuper = true)
-public class AwsComputationalTerminateDTO extends ComputationalTerminateDTO {
-
-	@JsonProperty("emr_cluster_name")
-	private String clusterName;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/ClusterConfig.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/ClusterConfig.java
deleted file mode 100644
index e8f791e..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/ClusterConfig.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.dto.aws.computational;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import org.hibernate.validator.constraints.NotEmpty;
-
-import javax.validation.constraints.NotNull;
-import java.util.List;
-import java.util.Map;
-
-@Data
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class ClusterConfig {
-	@JsonProperty("Classification")
-	@NotEmpty(message = "'Classification' field should not be empty")
-	private String classification;
-	@JsonProperty("Properties")
-	@NotNull(message = "'Properties' field should not be empty")
-	private Map<String, Object> properties;
-	@JsonProperty("Configurations")
-	private List<ClusterConfig> configurations;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/ComputationalConfigAws.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/ComputationalConfigAws.java
deleted file mode 100644
index 87996cc..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/ComputationalConfigAws.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.dto.aws.computational;
-
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-public class ComputationalConfigAws extends ComputationalBase<ComputationalConfigAws> {
-    @JsonProperty("emr_version")
-    private String version;
-
-    public String getVersion() {
-        return version;
-    }
-
-    public void setVersion(String version) {
-        this.version = version;
-    }
-
-    public ComputationalConfigAws withVersion(String version) {
-        setVersion(version);
-        return this;
-    }
-
-    @Override
-    public ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("version", version);
-    }
-
-    @Override
-    public String toString() {
-        return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/ComputationalCreateAws.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/ComputationalCreateAws.java
deleted file mode 100644
index 77021e0..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/ComputationalCreateAws.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * 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.dto.aws.computational;
-
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import java.util.List;
-
-public class ComputationalCreateAws extends ComputationalBase<ComputationalCreateAws> {
-	@JsonProperty("emr_instance_count")
-	private String instanceCount;
-	@JsonProperty("emr_master_instance_type")
-	private String masterInstanceType;
-	@JsonProperty("emr_slave_instance_type")
-	private String slaveInstanceType;
-	@JsonProperty("emr_slave_instance_spot")
-	private Boolean slaveInstanceSpot;
-	@JsonProperty("emr_slave_instance_spot_pct_price")
-	private Integer slaveInstanceSpotPctPrice;
-	@JsonProperty("emr_version")
-	private String version;
-	@JsonProperty("emr_configurations")
-	private List<ClusterConfig> config;
-	@JsonProperty("conf_shared_image_enabled")
-	private String sharedImageEnabled;
-
-	public String getInstanceCount() {
-		return instanceCount;
-	}
-
-	public void setInstanceCount(String instanceCount) {
-		this.instanceCount = instanceCount;
-	}
-
-	public ComputationalCreateAws withInstanceCount(String instanceCount) {
-		setInstanceCount(instanceCount);
-		return this;
-	}
-
-	public String getMasterInstanceType() {
-		return masterInstanceType;
-	}
-
-	public void setMasterInstanceType(String masterInstanceType) {
-		this.masterInstanceType = masterInstanceType;
-	}
-
-	public ComputationalCreateAws withMasterInstanceType(String masterInstanceType) {
-		setMasterInstanceType(masterInstanceType);
-		return this;
-	}
-
-	public String getSlaveInstanceType() {
-		return slaveInstanceType;
-	}
-
-	public void setSlaveInstanceType(String slaveInstanceType) {
-		this.slaveInstanceType = slaveInstanceType;
-	}
-
-	public ComputationalCreateAws withSlaveInstanceType(String slaveInstanceType) {
-		setSlaveInstanceType(slaveInstanceType);
-		return this;
-	}
-
-	public Boolean getSlaveInstanceSpot() {
-		return slaveInstanceSpot;
-	}
-
-	public void setSlaveInstanceSpot(Boolean slaveInstanceSpot) {
-		this.slaveInstanceSpot = slaveInstanceSpot;
-	}
-
-	public ComputationalCreateAws withSlaveInstanceSpot(Boolean slaveInstanceSpot) {
-		setSlaveInstanceSpot(slaveInstanceSpot);
-		return this;
-	}
-
-	public Integer getSlaveInstanceSpotPctPrice() {
-		return slaveInstanceSpotPctPrice;
-	}
-
-	public void setSlaveInstanceSpotPctPrice(Integer slaveInstanceSpotPctPrice) {
-		this.slaveInstanceSpotPctPrice = slaveInstanceSpotPctPrice;
-	}
-
-	public ComputationalCreateAws withSlaveInstanceSpotPctPrice(Integer slaveInstanceSpotPctPrice) {
-		setSlaveInstanceSpotPctPrice(slaveInstanceSpotPctPrice);
-		return this;
-	}
-
-	public String getVersion() {
-		return version;
-	}
-
-	public void setVersion(String version) {
-		this.version = version;
-	}
-
-	public ComputationalCreateAws withVersion(String version) {
-		setVersion(version);
-		return this;
-	}
-
-	public List<ClusterConfig> getConfig() {
-		return config;
-	}
-
-	public void setConfig(List<ClusterConfig> config) {
-		this.config = config;
-	}
-
-	public ComputationalCreateAws withConfig(List<ClusterConfig> config) {
-		setConfig(config);
-		return this;
-	}
-
-	public String getSharedImageEnabled() {
-		return sharedImageEnabled;
-	}
-
-	public void setSharedImageEnabled(String sharedImageEnabled) {
-		this.sharedImageEnabled = sharedImageEnabled;
-	}
-
-	public ComputationalCreateAws withSharedImageEnabled(String sharedImageEnabled) {
-		setSharedImageEnabled(sharedImageEnabled);
-		return this;
-	}
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("version", version)
-				.add("masterInstanceType", masterInstanceType)
-				.add("slaveInstanceType", slaveInstanceType)
-				.add("slaveInstanceSpot", slaveInstanceSpot)
-				.add("slaveInstanceSpotPctPrice", slaveInstanceSpotPctPrice)
-				.add("instanceCount", instanceCount);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/SparkComputationalConfigAws.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/SparkComputationalConfigAws.java
deleted file mode 100644
index 51712f7..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/SparkComputationalConfigAws.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.dto.aws.computational;
-
-import com.epam.dlab.dto.azure.computational.SparkComputationalConfigAzure;
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-public class SparkComputationalConfigAws extends ComputationalBase<SparkComputationalConfigAzure> {
-
-    @JsonProperty("dataengine_instance_count")
-    private String dataEngineInstanceCount;
-
-    public SparkComputationalConfigAws withDataEngineInstanceCount(String dataEngineInstanceCount) {
-        this.dataEngineInstanceCount = dataEngineInstanceCount;
-        return this;
-    }
-
-    @Override
-    public MoreObjects.ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("dataEngineInstanceCount", dataEngineInstanceCount);
-    }
-
-    @Override
-    public String toString() {
-        return toStringHelper(this).toString();
-    }
-
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/SparkComputationalCreateAws.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/SparkComputationalCreateAws.java
deleted file mode 100644
index 539937e..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/SparkComputationalCreateAws.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.dto.aws.computational;
-
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-import java.util.List;
-
-public class SparkComputationalCreateAws extends ComputationalBase<SparkComputationalCreateAws> {
-
-	@JsonProperty("dataengine_instance_count")
-	private String dataEngineInstanceCount;
-	@JsonProperty("aws_dataengine_slave_shape")
-	private String dataEngineSlaveShape;
-	@JsonProperty("aws_dataengine_master_shape")
-	private String dataEngineMasterShape;
-	@JsonProperty("spark_configurations")
-	private List<ClusterConfig> config;
-	@JsonProperty("conf_shared_image_enabled")
-	private String sharedImageEnabled;
-
-	public SparkComputationalCreateAws withDataEngineInstanceCount(String dataEngineInstanceCount) {
-		this.dataEngineInstanceCount = dataEngineInstanceCount;
-		return this;
-	}
-
-	public SparkComputationalCreateAws withDataEngineSlaveShape(String dataEngineSlaveSize) {
-		this.dataEngineSlaveShape = dataEngineSlaveSize;
-		return this;
-	}
-
-	public SparkComputationalCreateAws withDataEngineMasterShape(String dataEngineMasterSize) {
-		this.dataEngineMasterShape = dataEngineMasterSize;
-		return this;
-	}
-
-	public SparkComputationalCreateAws withConfig(List<ClusterConfig> config) {
-		this.config = config;
-		return this;
-	}
-
-	public SparkComputationalCreateAws withSharedImageEnabled(String sharedImageEnabled) {
-		this.sharedImageEnabled = sharedImageEnabled;
-		return this;
-	}
-
-	@Override
-	public MoreObjects.ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("dataEngineInstanceCount", dataEngineInstanceCount)
-				.add("dataEngineSlaveShape", dataEngineSlaveShape)
-				.add("dataEngineMasterShape", dataEngineMasterShape);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/edge/EdgeCreateAws.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/edge/EdgeCreateAws.java
deleted file mode 100644
index 8cc787d..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/edge/EdgeCreateAws.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.dto.aws.edge;
-
-import com.epam.dlab.dto.ResourceSysBaseDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-public class EdgeCreateAws extends ResourceSysBaseDTO<EdgeCreateAws> {
-    @JsonProperty("edge_elastic_ip")
-    private String edgeElasticIp;
-
-    public String getEdgeElasticIp() {
-        return edgeElasticIp;
-    }
-
-    public void setEdgeElasticIp(String edgeElasticIp) {
-        this.edgeElasticIp = edgeElasticIp;
-    }
-
-    public EdgeCreateAws withEdgeElasticIp(String edgeElasticIp) {
-        setEdgeElasticIp(edgeElasticIp);
-        return this;
-    }
-
-    @Override
-    public ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("edgeElasticIp", edgeElasticIp);
-    }
-
-    @Override
-    public String toString() {
-        return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/edge/EdgeInfoAws.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/edge/EdgeInfoAws.java
deleted file mode 100644
index 7ba2755..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/edge/EdgeInfoAws.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.dto.aws.edge;
-
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-@Getter
-@Setter
-@ToString(callSuper = true)
-@EqualsAndHashCode(callSuper = true)
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class EdgeInfoAws extends EdgeInfo {
-    @JsonProperty("user_own_bicket_name")
-    private String userOwnBucketName;
-    @JsonProperty("notebook_profile")
-    private String notebookProfile;
-    @JsonProperty("shared_bucket_name")
-    private String sharedBucketName;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/exploratory/ExploratoryCreateAws.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/exploratory/ExploratoryCreateAws.java
deleted file mode 100644
index 58d83df..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/exploratory/ExploratoryCreateAws.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.dto.aws.exploratory;
-
-import com.epam.dlab.dto.exploratory.ExploratoryCreateDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-public class ExploratoryCreateAws extends ExploratoryCreateDTO<ExploratoryCreateAws> {
-    @JsonProperty("aws_notebook_instance_type")
-    private String notebookInstanceType;
-
-    public String getNotebookInstanceType() {
-        return notebookInstanceType;
-    }
-
-    public void setNotebookInstanceType(String notebookInstanceType) {
-        this.notebookInstanceType = notebookInstanceType;
-    }
-
-    public ExploratoryCreateAws withNotebookInstanceType(String notebookInstanceType) {
-        setNotebookInstanceType(notebookInstanceType);
-        return this;
-    }
-
-    @Override
-    public MoreObjects.ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("notebookInstanceType", notebookInstanceType);
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/keyload/UploadFileAws.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/keyload/UploadFileAws.java
deleted file mode 100644
index b5bdd29..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/keyload/UploadFileAws.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.dto.aws.keyload;
-
-import com.epam.dlab.dto.aws.edge.EdgeCreateAws;
-import com.epam.dlab.dto.base.keyload.UploadFile;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@Data
-@ToString(callSuper = true)
-@EqualsAndHashCode(callSuper = true)
-public class UploadFileAws extends UploadFile {
-    @JsonProperty
-    private EdgeCreateAws edge;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/AzureCloudSettings.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/AzureCloudSettings.java
deleted file mode 100644
index 07013c6..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/AzureCloudSettings.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.dto.azure;
-
-import com.epam.dlab.dto.base.CloudSettings;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.*;
-
-@Data
-@ToString(callSuper = true)
-@EqualsAndHashCode(callSuper = true)
-@NoArgsConstructor
-@AllArgsConstructor
-@Builder
-public class AzureCloudSettings extends CloudSettings {
-
-    @JsonProperty("azure_region")
-    private String azureRegion;
-    @JsonProperty("azure_iam_user")
-    private String azureIamUser;
-    @JsonProperty("conf_service_base_name")
-    protected String sbn;
-    @JsonProperty("conf_os_family")
-    protected String os;
-    @JsonProperty("conf_cloud_provider")
-    protected String cloud;
-    @JsonProperty("azure_vpc_name")
-    private String azureVpcName;
-    @JsonProperty("azure_subnet_name")
-    private String azureSubnetName;
-    @JsonProperty("azure_resource_group_name")
-    private String azureResourceGroupName;
-    @JsonProperty("azure_security_group_name")
-    private String azureSecurityGroupName;
-    @JsonProperty("ldap_hostname")
-    protected String ldapHost;
-    @JsonProperty("ldap_dn")
-    protected String ldapDn;
-    @JsonProperty("ldap_ou")
-    protected String ldapOu;
-    @JsonProperty("ldap_service_username")
-    protected String ldapUser;
-    @JsonProperty("ldap_service_password")
-    protected String ldapPassword;
-    @JsonProperty("conf_key_dir")
-    protected String confKeyDir;
-    @JsonProperty("conf_image_enabled")
-    private String imageEnabled;
-    @JsonProperty("conf_stepcerts_enabled")
-    private String stepCertsEnabled;
-    @JsonProperty("conf_stepcerts_root_ca")
-    private String stepCertsRootCA;
-    @JsonProperty("conf_stepcerts_kid")
-    private String stepCertsKid;
-    @JsonProperty("conf_stepcerts_kid_password")
-    private String stepCertsKidPassword;
-    @JsonProperty("conf_stepcerts_ca_url")
-    private String stepCertsCAURL;
-    @JsonProperty("keycloak_auth_server_url")
-    private String keycloakAuthServerUrl;
-    @JsonProperty("keycloak_realm_name")
-    private String keycloakRealmName;
-    @JsonProperty("keycloak_user")
-    private String keycloakUser;
-    @JsonProperty("keycloak_user_password")
-    private String keycloakUserPassword;
-
-    @Override
-    @JsonIgnore
-    public String getIamUser() {
-        return azureIamUser;
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/auth/AuthorizationCodeFlowResponse.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/auth/AuthorizationCodeFlowResponse.java
deleted file mode 100644
index 14f186b..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/auth/AuthorizationCodeFlowResponse.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.dto.azure.auth;
-
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.ToString;
-
-import javax.ws.rs.FormParam;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-@ToString(exclude = "code")
-public class AuthorizationCodeFlowResponse {
-
-    @JsonProperty
-    @FormParam("state")
-    private String state;
-    @JsonProperty
-    @FormParam("code")
-    private String code;
-    @JsonProperty
-    @FormParam("error")
-    private String error;
-    @JsonProperty("error_description")
-    @FormParam("error_description")
-    private String errorDescription;
-
-    @JsonIgnore
-    public boolean isSuccessful() {
-        return state != null && !state.isEmpty() && code != null && !code.isEmpty();
-    }
-
-    @JsonIgnore
-    public boolean isFailed() {
-        return error != null && !error.isEmpty();
-    }
-
-    @JsonIgnore
-    public boolean isValid() {
-        return isSuccessful() || isFailed();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/computational/SparkComputationalConfigAzure.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/computational/SparkComputationalConfigAzure.java
deleted file mode 100644
index 882ddbe..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/computational/SparkComputationalConfigAzure.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.dto.azure.computational;
-
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-public class SparkComputationalConfigAzure extends ComputationalBase<SparkComputationalConfigAzure> {
-
-    @JsonProperty("dataengine_instance_count")
-    private String dataEngineInstanceCount;
-
-    public SparkComputationalConfigAzure withDataEngineInstanceCount(String dataEngineInstanceCount) {
-        this.dataEngineInstanceCount = dataEngineInstanceCount;
-        return this;
-    }
-
-    @Override
-    public MoreObjects.ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("dataEngineInstanceCount", dataEngineInstanceCount);
-    }
-
-    @Override
-    public String toString() {
-        return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/computational/SparkComputationalCreateAzure.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/computational/SparkComputationalCreateAzure.java
deleted file mode 100644
index 5902906..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/computational/SparkComputationalCreateAzure.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.dto.azure.computational;
-
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-import java.util.List;
-
-public class SparkComputationalCreateAzure extends ComputationalBase<SparkComputationalCreateAzure> {
-	@JsonProperty("dataengine_instance_count")
-	private String dataEngineInstanceCount;
-	@JsonProperty("azure_dataengine_slave_size")
-	private String dataEngineSlaveSize;
-	@JsonProperty("azure_dataengine_master_size")
-	private String dataEngineMasterSize;
-	@JsonProperty("azure_datalake_enable")
-	private String azureDataLakeEnabled;
-	@JsonProperty("azure_user_refresh_token")
-	private String azureUserRefreshToken;
-	@JsonProperty("spark_configurations")
-	private List<ClusterConfig> config;
-	@JsonProperty("conf_shared_image_enabled")
-	private String sharedImageEnabled;
-
-	public SparkComputationalCreateAzure withDataEngineInstanceCount(String dataEngineInstanceCount) {
-		this.dataEngineInstanceCount = dataEngineInstanceCount;
-		return this;
-	}
-
-	public SparkComputationalCreateAzure withDataEngineSlaveSize(String dataEngineSlaveSize) {
-		this.dataEngineSlaveSize = dataEngineSlaveSize;
-		return this;
-	}
-
-	public SparkComputationalCreateAzure withDataEngineMasterSize(String dataEngineMasterSize) {
-		this.dataEngineMasterSize = dataEngineMasterSize;
-		return this;
-	}
-
-	public SparkComputationalCreateAzure withAzureDataLakeEnabled(String azureDataLakeEnabled) {
-		this.azureDataLakeEnabled = azureDataLakeEnabled;
-		return this;
-	}
-
-	public SparkComputationalCreateAzure withAzureUserRefreshToken(String azureUserRefreshToken) {
-		this.azureUserRefreshToken = azureUserRefreshToken;
-		return this;
-	}
-
-	public SparkComputationalCreateAzure withConfig(List<ClusterConfig> config) {
-		this.config = config;
-		return this;
-	}
-
-	public SparkComputationalCreateAzure withSharedImageEnabled(String sharedImageEnabled) {
-		this.sharedImageEnabled = sharedImageEnabled;
-		return this;
-	}
-
-	@Override
-	public MoreObjects.ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("dataEngineInstanceCount", dataEngineInstanceCount)
-				.add("dataEngineSlaveSize", dataEngineSlaveSize)
-				.add("dataEngineMasterSize", dataEngineMasterSize)
-				.add("azureDataLakeEnabled", azureDataLakeEnabled)
-				.add("azureUserRefreshToken", azureUserRefreshToken != null ? "***" : null);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/edge/EdgeCreateAzure.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/edge/EdgeCreateAzure.java
deleted file mode 100644
index 9297150..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/edge/EdgeCreateAzure.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.dto.azure.edge;
-
-import com.epam.dlab.dto.ResourceSysBaseDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-public class EdgeCreateAzure extends ResourceSysBaseDTO<EdgeCreateAzure> {
-    @JsonProperty("azure_datalake_enable")
-    private String azureDataLakeEnable;
-
-    public EdgeCreateAzure withAzureDataLakeEnable(String azureDataLakeEnable) {
-        this.azureDataLakeEnable = azureDataLakeEnable;
-        return this;
-    }
-
-    public String getAzureDataLakeEnable() {
-        return azureDataLakeEnable;
-    }
-
-
-    public void setAzureDataLakeEnable(String azureDataLakeEnable) {
-        this.azureDataLakeEnable = azureDataLakeEnable;
-    }
-
-    @Override
-    public MoreObjects.ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(this)
-                .add("azureDataLakeEnable", azureDataLakeEnable);
-    }
-
-    @Override
-    public String toString() {
-        return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/edge/EdgeInfoAzure.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/edge/EdgeInfoAzure.java
deleted file mode 100644
index 9564261..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/edge/EdgeInfoAzure.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.dto.azure.edge;
-
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-@Getter
-@Setter
-@ToString(callSuper = true)
-@EqualsAndHashCode(callSuper = true)
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class EdgeInfoAzure extends EdgeInfo {
-    @JsonProperty("user_storage_account_name")
-    private String userStorageAccountName;
-    @JsonProperty("user_container_name")
-    private String userContainerName;
-    @JsonProperty("shared_storage_account_name")
-    private String sharedStorageAccountName;
-    @JsonProperty("shared_container_name")
-    private String sharedContainerName;
-    @JsonProperty("user_storage_account_tag_name")
-    private String userStorageAccountTagName;
-    @JsonProperty("datalake_name")
-    private String dataLakeName;
-    @JsonProperty("datalake_user_directory_name")
-    private String dataLakeDirectoryName;
-    @JsonProperty("datalake_shared_directory_name")
-    private String dataLakeSharedDirectoryName;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/exploratory/ExploratoryActionStartAzure.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/exploratory/ExploratoryActionStartAzure.java
deleted file mode 100644
index 48c314a..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/exploratory/ExploratoryActionStartAzure.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.dto.azure.exploratory;
-
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-public class ExploratoryActionStartAzure extends ExploratoryGitCredsUpdateDTO {
-	@JsonProperty("azure_datalake_enable")
-	private String azureDataLakeEnabled;
-	@JsonProperty("azure_user_refresh_token")
-	private String azureUserRefreshToken;
-
-	public String getAzureDataLakeEnabled() {
-		return azureDataLakeEnabled;
-	}
-
-	public void setAzureDataLakeEnabled(String azureDataLakeEnabled) {
-		this.azureDataLakeEnabled = azureDataLakeEnabled;
-	}
-
-	public String getAzureUserRefreshToken() {
-		return azureUserRefreshToken;
-	}
-
-	public void setAzureUserRefreshToken(String azureUserRefreshToken) {
-		this.azureUserRefreshToken = azureUserRefreshToken;
-	}
-
-	public ExploratoryActionStartAzure withAzureDataLakeEnabled(String azureDataLakeEnabled) {
-		setAzureDataLakeEnabled(azureDataLakeEnabled);
-		return this;
-	}
-
-	public ExploratoryActionStartAzure withAzureUserRefreshToken(String azureUserRefreshToken) {
-		setAzureUserRefreshToken(azureUserRefreshToken);
-		return this;
-	}
-
-	@Override
-	public MoreObjects.ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("azureDataLakeEnabled", azureDataLakeEnabled)
-				.add("azureUserRefreshToken", azureUserRefreshToken != null ? "***" : null);
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/exploratory/ExploratoryActionStopAzure.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/exploratory/ExploratoryActionStopAzure.java
deleted file mode 100644
index 1915106..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/exploratory/ExploratoryActionStopAzure.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.dto.azure.exploratory;
-
-import com.epam.dlab.dto.exploratory.ExploratoryActionDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-public class ExploratoryActionStopAzure extends ExploratoryActionDTO<ExploratoryActionStopAzure> {
-    @JsonProperty("computational_name")
-    private String computationalName;
-
-    public String getComputationalName() {
-        return computationalName;
-    }
-
-    public ExploratoryActionStopAzure setComputationalName(String computationalName) {
-        this.computationalName = computationalName;
-        return this;
-    }
-
-    @Override
-    public MoreObjects.ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("computationalName", computationalName);
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/exploratory/ExploratoryCreateAzure.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/exploratory/ExploratoryCreateAzure.java
deleted file mode 100644
index bb2b443..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/exploratory/ExploratoryCreateAzure.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.dto.azure.exploratory;
-
-import com.epam.dlab.dto.exploratory.ExploratoryCreateDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-public class ExploratoryCreateAzure extends ExploratoryCreateDTO<ExploratoryCreateAzure> {
-    @JsonProperty("azure_notebook_instance_size")
-    private String notebookInstanceType;
-    @JsonProperty("azure_datalake_enable")
-    private String azureDataLakeEnabled;
-    @JsonProperty("azure_user_refresh_token")
-    private String azureUserRefreshToken;
-
-    public String getNotebookInstanceType() {
-        return notebookInstanceType;
-    }
-
-    public void setNotebookInstanceType(String notebookInstanceType) {
-        this.notebookInstanceType = notebookInstanceType;
-    }
-
-    public String getAzureDataLakeEnabled() {
-        return azureDataLakeEnabled;
-    }
-
-    public void setAzureDataLakeEnabled(String azureDataLakeEnabled) {
-        this.azureDataLakeEnabled = azureDataLakeEnabled;
-    }
-
-    public String getAzureUserRefreshToken() {
-        return azureUserRefreshToken;
-    }
-
-    public void setAzureUserRefreshToken(String azureUserRefreshToken) {
-        this.azureUserRefreshToken = azureUserRefreshToken;
-    }
-
-    public ExploratoryCreateAzure withNotebookInstanceSize(String notebookInstanceType) {
-        setNotebookInstanceType(notebookInstanceType);
-        return this;
-    }
-
-    public ExploratoryCreateAzure withAzureDataLakeEnabled(String azureDataLakeEnabled) {
-        setAzureDataLakeEnabled(azureDataLakeEnabled);
-        return this;
-    }
-
-    public ExploratoryCreateAzure withAzureUserRefreshToken(String azureUserRefreshToken) {
-        setAzureUserRefreshToken(azureUserRefreshToken);
-        return this;
-    }
-
-    @Override
-    public MoreObjects.ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("notebookInstanceType", notebookInstanceType)
-                .add("azureDataLakeEnabled", azureDataLakeEnabled)
-                .add("azureUserRefreshToken", azureUserRefreshToken != null ? "***" : null);
-    }
-
-    @Override
-    public String toString() {
-        return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/keyload/UploadFileAzure.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/keyload/UploadFileAzure.java
deleted file mode 100644
index 398ef6d..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/keyload/UploadFileAzure.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.dto.azure.keyload;
-
-import com.epam.dlab.dto.azure.edge.EdgeCreateAzure;
-import com.epam.dlab.dto.base.keyload.UploadFile;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@Data
-@ToString(callSuper = true)
-@EqualsAndHashCode(callSuper = true)
-public class UploadFileAzure extends UploadFile {
-    @JsonProperty
-    private EdgeCreateAzure edge;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/backup/EnvBackupDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/backup/EnvBackupDTO.java
deleted file mode 100644
index 5442cb8..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/backup/EnvBackupDTO.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.dto.backup;
-
-import lombok.Builder;
-import lombok.Data;
-import lombok.ToString;
-
-import java.util.List;
-
-@Data
-@Builder
-@ToString
-public class EnvBackupDTO {
-	private final List<String> configFiles;
-	private final List<String> keys;
-	private final List<String> certificates;
-	private final List<String> jars;
-	private final boolean databaseBackup;
-	private final boolean logsBackup;
-	private String backupFile;
-	private String id;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/backup/EnvBackupStatus.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/backup/EnvBackupStatus.java
deleted file mode 100644
index 13c3efb..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/backup/EnvBackupStatus.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.dto.backup;
-
-import java.util.Arrays;
-
-public enum EnvBackupStatus {
-	CREATING("N/A"), CREATED("N/A"), FAILED("N/A");
-
-	private String message;
-
-	EnvBackupStatus(String message) {
-		this.message = message;
-	}
-
-	public EnvBackupStatus withErrorMessage(String message) {
-		this.message = message;
-		return this;
-	}
-
-	public String message() {
-		return message;
-	}
-
-	public static EnvBackupStatus fromValue(String value) {
-		return Arrays.stream(values())
-				.filter(v -> v.name().equalsIgnoreCase(value))
-				.findAny()
-				.orElseThrow(() ->
-						new IllegalArgumentException("Wrong value for EnvBackupStatus: " + value));
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/backup/EnvBackupStatusDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/backup/EnvBackupStatusDTO.java
deleted file mode 100644
index 6beae62..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/backup/EnvBackupStatusDTO.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.dto.backup;
-
-import com.epam.dlab.dto.StatusBaseDTO;
-import com.google.common.base.MoreObjects;
-import lombok.Getter;
-
-@Getter
-public class EnvBackupStatusDTO extends StatusBaseDTO<EnvBackupStatusDTO> {
-
-	private EnvBackupDTO envBackupDTO;
-	private EnvBackupStatus envBackupStatus;
-
-
-	public EnvBackupStatusDTO withEnvBackupDTO(EnvBackupDTO envBackupDTO) {
-		this.envBackupDTO = envBackupDTO;
-		return this;
-	}
-
-	public EnvBackupStatusDTO withStatus(EnvBackupStatus status) {
-		this.envBackupStatus = status;
-		return withStatus(status.name());
-	}
-
-	public EnvBackupStatusDTO withBackupFile(String backupFile) {
-		if (envBackupDTO != null) {
-			envBackupDTO.setBackupFile(backupFile);
-		}
-		return this;
-	}
-
-	@Override
-	public MoreObjects.ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("envBackupStatus", envBackupStatus)
-				.add("envBackupDTO", envBackupDTO);
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/CloudSettings.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/CloudSettings.java
deleted file mode 100644
index 8e53c7d..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/CloudSettings.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.dto.base;
-
-import com.epam.dlab.util.CloudSettingsDeserializer;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import lombok.Data;
-
-@Data
-@JsonDeserialize(using = CloudSettingsDeserializer.class)
-public abstract class CloudSettings {
-	@JsonIgnore
-	public abstract String getIamUser();
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/DataEngineType.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/DataEngineType.java
deleted file mode 100644
index a9d8b03..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/DataEngineType.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.dto.base;
-
-import com.fasterxml.jackson.annotation.JsonValue;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public enum DataEngineType {
-	CLOUD_SERVICE("dataengine-service"), SPARK_STANDALONE("dataengine");
-
-	private static final String DOCKER_IMAGE_PREFIX = "docker.dlab-";
-
-	private static final Map<String, DataEngineType> INTERNAL_MAP = new HashMap<>();
-
-	static {
-		for (DataEngineType dataEngineType : DataEngineType.values()) {
-			INTERNAL_MAP.put(dataEngineType.getName(), dataEngineType);
-		}
-	}
-
-	private String name;
-
-	DataEngineType(String name) {
-		this.name = name;
-	}
-
-	public String getImage() {
-		return DOCKER_IMAGE_PREFIX + this.name;
-	}
-
-	public static DataEngineType fromString(String name) {
-		return INTERNAL_MAP.get(name);
-	}
-
-	public static DataEngineType fromDockerImageName(String name) {
-		return INTERNAL_MAP.get(name.replace(DOCKER_IMAGE_PREFIX, ""));
-	}
-
-	public static String getDockerImageName(DataEngineType dataEngineType) {
-		return DOCKER_IMAGE_PREFIX + dataEngineType.getName();
-	}
-
-	@JsonValue
-	public String getName() {
-		return name;
-	}
-}
\ No newline at end of file
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/computational/ComputationalBase.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/computational/ComputationalBase.java
deleted file mode 100644
index e3aa000..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/computational/ComputationalBase.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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.dto.base.computational;
-
-import com.epam.dlab.dto.ResourceEnvBaseDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import java.util.Map;
-
-public abstract class ComputationalBase<T extends ComputationalBase<?>> extends ResourceEnvBaseDTO<T> {
-	@SuppressWarnings("unchecked")
-	private final T self = (T) this;
-
-	@JsonProperty("computational_name")
-	private String computationalName;
-
-	@JsonProperty("notebook_instance_name")
-	private String notebookInstanceName;
-
-	@JsonProperty("notebook_template_name")
-	private String notebookTemplateName;
-
-	@JsonProperty("project_name")
-	private String project;
-	@JsonProperty("endpoint_name")
-	private String ednpoint;
-
-	@JsonProperty("tags")
-	private Map<String, String> tags;
-
-	public String getComputationalName() {
-		return computationalName;
-	}
-
-	public void setComputationalName(String computationalName) {
-		this.computationalName = computationalName;
-	}
-
-	public T withComputationalName(String computationalName) {
-		setComputationalName(computationalName);
-		return self;
-	}
-
-	public String getNotebookInstanceName() {
-		return notebookInstanceName;
-	}
-
-	public void setNotebookInstanceName(String notebookInstanceName) {
-		this.notebookInstanceName = notebookInstanceName;
-	}
-
-	public T withNotebookInstanceName(String notebookInstanceName) {
-		setNotebookInstanceName(notebookInstanceName);
-		return self;
-	}
-
-	public String getNotebookTemplateName() {
-		return notebookTemplateName;
-	}
-
-	public void setNotebookTemplateName(String notebookTemplateName) {
-		this.notebookTemplateName = notebookTemplateName;
-	}
-
-	public T withNotebookTemplateName(String notebookTemplateName) {
-		setNotebookTemplateName(notebookTemplateName);
-		return self;
-	}
-
-	public T withProject(String project) {
-		this.project = project;
-		return self;
-	}
-
-	public T withTags(Map<String, String> tags) {
-		this.tags = tags;
-		return self;
-	}
-
-	public T withEndpoint(String endpoint) {
-		this.ednpoint = endpoint;
-		return self;
-	}
-
-	public String getProject() {
-		return project;
-	}
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("computationalName", computationalName)
-				.add("notebookInstanceName", notebookInstanceName)
-				.add("notebookTemplateName", notebookTemplateName);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/computational/FullComputationalTemplate.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/computational/FullComputationalTemplate.java
deleted file mode 100644
index 0c23ef2..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/computational/FullComputationalTemplate.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.dto.base.computational;
-
-import com.epam.dlab.dto.imagemetadata.ComputationalMetadataDTO;
-import com.fasterxml.jackson.annotation.JsonUnwrapped;
-
-public class FullComputationalTemplate {
-	@JsonUnwrapped
-	private ComputationalMetadataDTO computationalMetadataDTO;
-
-
-	public FullComputationalTemplate(ComputationalMetadataDTO metadataDTO) {
-		this.computationalMetadataDTO = metadataDTO;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/edge/EdgeInfo.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/edge/EdgeInfo.java
deleted file mode 100644
index ddcf8c4..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/edge/EdgeInfo.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.dto.base.edge;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import lombok.Data;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
-public class EdgeInfo {
-	@JsonProperty("_id")
-	@JsonInclude(JsonInclude.Include.NON_EMPTY)
-	private String id;
-
-	@JsonProperty("instance_id")
-	private String instanceId;
-
-	@JsonProperty
-	private String hostname;
-
-	@JsonProperty("public_ip")
-	private String publicIp;
-
-	@JsonProperty
-	private String ip;
-
-	@JsonProperty("key_name")
-	private String keyName;
-
-	@JsonProperty("tunnel_port")
-	private String tunnelPort;
-
-	@JsonProperty("socks_port")
-	private String socksPort;
-
-	@JsonProperty("notebook_sg")
-	private String notebookSg;
-
-	@JsonProperty("edge_sg")
-	private String edgeSg;
-
-	@JsonProperty("notebook_subnet")
-	private String notebookSubnet;
-
-	@JsonProperty("edge_status")
-	private String edgeStatus;
-
-	@JsonProperty("reupload_key_required")
-	private boolean reuploadKeyRequired = false;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/keyload/ReuploadFile.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/keyload/ReuploadFile.java
deleted file mode 100644
index 109f0b1..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/keyload/ReuploadFile.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.dto.base.keyload;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@Data
-@ToString(callSuper = true)
-@EqualsAndHashCode(callSuper = true)
-public class ReuploadFile extends UploadFile {
-	@JsonProperty
-	private String edgeUserName;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/keyload/UploadFile.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/keyload/UploadFile.java
deleted file mode 100644
index 65ee00c..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/keyload/UploadFile.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.dto.base.keyload;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class UploadFile {
-    @JsonProperty
-    private String content;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/keyload/UploadFileResult.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/keyload/UploadFileResult.java
deleted file mode 100644
index 96c9943..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/keyload/UploadFileResult.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.dto.base.keyload;
-
-import com.epam.dlab.dto.StatusBaseDTO;
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-import com.google.common.base.MoreObjects;
-
-public class UploadFileResult<T extends EdgeInfo> extends StatusBaseDTO<UploadFileResult<T>> {
-
-    private T edgeInfo;
-
-    public T getEdgeInfo() {
-        return edgeInfo;
-    }
-
-    public UploadFileResult<T> withEdgeInfo(T edgeInfo) {
-        this.edgeInfo = edgeInfo;
-        return this;
-    }
-
-    @Override
-    public MoreObjects.ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("edgeInfo", edgeInfo);
-    }
-
-
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/project/ProjectResult.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/project/ProjectResult.java
deleted file mode 100644
index 9134f4a..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/project/ProjectResult.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.dto.base.project;
-
-import com.epam.dlab.dto.StatusBaseDTO;
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class ProjectResult extends StatusBaseDTO<ProjectResult> {
-	private EdgeInfo edgeInfo;
-	@JsonProperty("project_name")
-	private String projectName;
-	@JsonProperty("endpoint_name")
-	private String endpointName;
-
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/billing/BillingData.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/billing/BillingData.java
deleted file mode 100644
index c95a02e..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/billing/BillingData.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.dto.billing;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Data;
-
-import java.time.LocalDate;
-
-@Data
-@Builder
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class BillingData {
-    private final String tag;
-    private String application;
-    @JsonProperty("from")
-    private LocalDate usageDateFrom;
-    @JsonProperty("to")
-    private LocalDate usageDateTo;
-    private String product;
-    private String usageType;
-    private Double cost;
-    private String currency;
-    private final String usageDate;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/billing/BillingResourceType.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/billing/BillingResourceType.java
deleted file mode 100644
index 7ad1082..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/billing/BillingResourceType.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.dto.billing;
-
-public enum BillingResourceType {
-    EDGE,
-    SSN,
-    ENDPOINT,
-    BUCKET,
-    VOLUME,
-    EXPLORATORY,
-    COMPUTATIONAL,
-    IMAGE
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/BucketDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/BucketDTO.java
deleted file mode 100644
index 369c866..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/BucketDTO.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.dto.bucket;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.Builder;
-import lombok.Data;
-
-@Data
-@Builder
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class BucketDTO {
-    private final String bucket;
-    private final String object;
-    private final String size;
-    private final String lastModifiedDate;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/BucketDeleteDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/BucketDeleteDTO.java
deleted file mode 100644
index 0bec33d..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/BucketDeleteDTO.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.dto.bucket;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class BucketDeleteDTO {
-    private final String bucket;
-    private final List<String> objects;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/FolderUploadDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/FolderUploadDTO.java
deleted file mode 100644
index 453b16f..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/bucket/FolderUploadDTO.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.dto.bucket;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.Data;
-import org.hibernate.validator.constraints.NotBlank;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class FolderUploadDTO {
-    @NotBlank(message = "field cannot be empty")
-    private final String bucket;
-    @NotBlank(message = "field cannot be empty")
-    private final String folder;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/CheckInactivityCallbackDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/CheckInactivityCallbackDTO.java
deleted file mode 100644
index d7b790b..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/CheckInactivityCallbackDTO.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.dto.computational;
-
-import com.epam.dlab.dto.ResourceBaseDTO;
-import com.epam.dlab.dto.status.EnvResource;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.util.List;
-
-@Setter
-@Getter
-public class CheckInactivityCallbackDTO extends ResourceBaseDTO<CheckInactivityCallbackDTO> {
-
-	@JsonProperty
-	private List<EnvResource> resources;
-
-	@JsonProperty
-	private String id;
-
-	public CheckInactivityCallbackDTO withClusters(List<EnvResource> clusters) {
-		setResources(clusters);
-		return this;
-	}
-
-	public CheckInactivityCallbackDTO withId(String id) {
-		this.id = id;
-		return this;
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this)
-				.add("resources", resources)
-				.add("id", id)
-				.toString();
-	}
-
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/CheckInactivityStatus.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/CheckInactivityStatus.java
deleted file mode 100644
index 38212d9..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/CheckInactivityStatus.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.dto.computational;
-
-import java.util.Arrays;
-
-public enum CheckInactivityStatus {
-
-	COMPLETED("N/A"), FAILED("N/A");
-
-	private String message;
-
-	CheckInactivityStatus(String message) {
-		this.message = message;
-	}
-
-	public CheckInactivityStatus withErrorMessage(String message) {
-		this.message = message;
-		return this;
-	}
-
-	public String message() {
-		return message;
-	}
-
-	public static CheckInactivityStatus fromValue(String value) {
-		return Arrays.stream(values())
-				.filter(v -> v.name().equalsIgnoreCase(value))
-				.findAny()
-				.orElseThrow(() ->
-						new IllegalArgumentException("Wrong value for CheckInactivityStatus: " + value));
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/CheckInactivityStatusDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/CheckInactivityStatusDTO.java
deleted file mode 100644
index 80e57cd..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/CheckInactivityStatusDTO.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.dto.computational;
-
-import com.epam.dlab.dto.StatusBaseDTO;
-import lombok.Data;
-
-@Data
-public class CheckInactivityStatusDTO extends StatusBaseDTO<CheckInactivityStatusDTO> {
-
-	private String exploratoryName;
-	private String computationalName;
-	private long lastActivityUnixTime;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalCheckInactivityDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalCheckInactivityDTO.java
deleted file mode 100644
index 1fc3291..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalCheckInactivityDTO.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.dto.computational;
-
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-public class ComputationalCheckInactivityDTO extends ComputationalBase<ComputationalCheckInactivityDTO> {
-	private String notebookImage;
-	@JsonProperty("computational_id")
-	private String computationalId;
-	private String image;
-
-	public ComputationalCheckInactivityDTO withNotebookImageName(String imageName) {
-		this.notebookImage = imageName;
-		return this;
-	}
-
-	public ComputationalCheckInactivityDTO withComputationalId(String computationalId) {
-		this.computationalId = computationalId;
-		return this;
-	}
-
-	public ComputationalCheckInactivityDTO withImage(String image) {
-		this.image = image;
-		return this;
-	}
-
-	public String getNotebookImage() {
-		return notebookImage;
-	}
-
-	public String getComputationalId() {
-		return computationalId;
-	}
-
-	public String getImage() {
-		return image;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalClusterConfigDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalClusterConfigDTO.java
deleted file mode 100644
index df60cb9..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalClusterConfigDTO.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.dto.computational;
-
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class ComputationalClusterConfigDTO extends ComputationalBase<ComputationalClusterConfigDTO> {
-
-    @JsonProperty("computational_id")
-    private String copmutationalId;
-    @JsonProperty("spark_configurations")
-    private List<ClusterConfig> config;
-    @JsonProperty("azure_user_refresh_token")
-    private String azureUserRefreshToken;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalStartDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalStartDTO.java
deleted file mode 100644
index aae7f7b..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalStartDTO.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.dto.computational;
-
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-
-public class ComputationalStartDTO extends ComputationalBase<ComputationalStartDTO> {
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalStatusDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalStatusDTO.java
deleted file mode 100644
index 241f92f..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalStatusDTO.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.dto.computational;
-
-import com.epam.dlab.dto.ResourceURL;
-import com.epam.dlab.dto.StatusEnvBaseDTO;
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import java.util.Date;
-import java.util.List;
-
-public class ComputationalStatusDTO extends StatusEnvBaseDTO<ComputationalStatusDTO> {
-	@JsonProperty("computational_url")
-	private List<ResourceURL> resourceUrl;
-	@JsonProperty("computational_id")
-	private String computationalId;
-	@JsonProperty("computational_name")
-	private String computationalName;
-	@JsonProperty("last_activity")
-	private Date lastActivity;
-	@JsonProperty
-	private List<ClusterConfig> config;
-
-	public String getComputationalId() {
-		return computationalId;
-	}
-
-	public void setComputationalId(String computationalId) {
-		this.computationalId = computationalId;
-	}
-
-	public ComputationalStatusDTO withComputationalId(String computationalId) {
-		setComputationalId(computationalId);
-		return this;
-	}
-
-	public List<ResourceURL> getResourceUrl() {
-		return resourceUrl;
-	}
-
-	public String getComputationalName() {
-		return computationalName;
-	}
-
-	public void setComputationalName(String computationalName) {
-		this.computationalName = computationalName;
-	}
-
-	public void setResourceUrl(List<ResourceURL> resourceUrl) {
-		this.resourceUrl = resourceUrl;
-	}
-
-	public void setLastActivity(Date lastActivity) {
-		this.lastActivity = lastActivity;
-	}
-
-	public ComputationalStatusDTO withComputationalUrl(List<ResourceURL> resourceUrl) {
-		setResourceUrl(resourceUrl);
-		return this;
-	}
-
-	public ComputationalStatusDTO withComputationalName(String computationalName) {
-		setComputationalName(computationalName);
-		return this;
-	}
-
-	public ComputationalStatusDTO withConfig(List<ClusterConfig> config) {
-		this.config = config;
-		return this;
-	}
-
-	public Date getLastActivity() {
-		return lastActivity;
-	}
-
-	public ComputationalStatusDTO withLastActivity(Date lastActivity) {
-		setLastActivity(lastActivity);
-		return this;
-	}
-
-	public List<ClusterConfig> getConfig() {
-		return config;
-	}
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("computationalUrl", resourceUrl)
-				.add("computationalId", computationalId)
-				.add("computationalName", computationalName)
-				.add("lastActivity", lastActivity)
-				.add("config", config);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalStopDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalStopDTO.java
deleted file mode 100644
index 7d3c5f6..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalStopDTO.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.dto.computational;
-
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-
-public class ComputationalStopDTO extends ComputationalBase<ComputationalStopDTO> {
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalTerminateDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalTerminateDTO.java
deleted file mode 100644
index 44b6460..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/ComputationalTerminateDTO.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.dto.computational;
-
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-
-public class ComputationalTerminateDTO extends ComputationalBase<ComputationalTerminateDTO> {
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/SparkStandaloneClusterResource.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/SparkStandaloneClusterResource.java
deleted file mode 100644
index b3f6539..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/SparkStandaloneClusterResource.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.dto.computational;
-
-import com.epam.dlab.dto.ResourceURL;
-import com.epam.dlab.dto.SchedulerJobDTO;
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-import org.hibernate.validator.constraints.NotBlank;
-
-import java.time.LocalDateTime;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class SparkStandaloneClusterResource extends UserComputationalResource {
-	@NotBlank
-	@JsonProperty("dataengine_instance_count")
-	private String dataEngineInstanceCount;
-
-	@NotBlank
-	@JsonProperty("dataengine_instance_shape")
-	private String dataEngineInstanceShape;
-
-	@Builder
-	public SparkStandaloneClusterResource(String computationalName, String computationalId, String imageName,
-										  String templateName, String status, Date uptime,
-										  SchedulerJobDTO schedulerJobData, boolean reuploadKeyRequired,
-										  String dataEngineInstanceCount, String dataEngineInstanceShape,
-										  List<ResourceURL> resourceURL, LocalDateTime lastActivity,
-										  List<ClusterConfig> config, Map<String, String> tags, int totalInstanceCount) {
-		super(computationalName, computationalId, imageName, templateName, status, uptime, schedulerJobData,
-				reuploadKeyRequired, resourceURL, lastActivity, tags, totalInstanceCount);
-		this.dataEngineInstanceCount = dataEngineInstanceCount;
-		this.dataEngineInstanceShape = dataEngineInstanceShape;
-		this.config = config;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/UserComputationalResource.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/UserComputationalResource.java
deleted file mode 100644
index aa25af4..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/UserComputationalResource.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.dto.computational;
-
-import com.epam.dlab.dto.ResourceURL;
-import com.epam.dlab.dto.SchedulerJobDTO;
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.time.LocalDateTime;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-@Data
-@NoArgsConstructor
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class UserComputationalResource {
-	@JsonProperty("computational_name")
-	private String computationalName;
-	@JsonProperty("computational_id")
-	private String computationalId;
-	@JsonProperty("image")
-	private String imageName;
-	@JsonProperty("template_name")
-	private String templateName;
-	@JsonProperty
-	private String status;
-	@JsonProperty("up_time")
-	private Date uptime;
-	@JsonProperty("scheduler_data")
-	private SchedulerJobDTO schedulerData;
-	@JsonProperty("reupload_key_required")
-	private boolean reuploadKeyRequired = false;
-	@JsonProperty("computational_url")
-	private List<ResourceURL> resourceUrl;
-	@JsonProperty("last_activity")
-	private LocalDateTime lastActivity;
-	@JsonProperty("master_node_shape")
-	private String masterNodeShape;
-	@JsonProperty("slave_node_shape")
-	private String slaveNodeShape;
-	@JsonProperty("dataengine_instance_shape")
-	private String dataengineShape;
-	@JsonProperty("dataengine_instance_count")
-	private int dataengineInstanceCount;
-	@JsonProperty("instance_id")
-	private String instanceId;
-	@JsonProperty("dataproc_version")
-	private String gcpClusterVersion;
-	@JsonProperty("emr_version")
-	private String awsClusterVersion;
-	private int totalInstanceCount;
-	protected List<ClusterConfig> config;
-	private Map<String, String> tags;
-
-	public UserComputationalResource(String computationalName, String computationalId, String imageName,
-									 String templateName, String status, Date uptime, SchedulerJobDTO schedulerData,
-									 boolean reuploadKeyRequired, List<ResourceURL> resourceUrl,
-									 LocalDateTime lastActivity, Map<String, String> tags, int totalInstanceCount) {
-		this.computationalName = computationalName;
-		this.computationalId = computationalId;
-		this.imageName = imageName;
-		this.templateName = templateName;
-		this.status = status;
-		this.uptime = uptime;
-		this.schedulerData = schedulerData;
-		this.reuploadKeyRequired = reuploadKeyRequired;
-		this.resourceUrl = resourceUrl;
-		this.lastActivity = lastActivity;
-		this.tags = tags;
-		this.totalInstanceCount = totalInstanceCount;
-	}
-
-	public DataEngineType getDataEngineType() {
-		return DataEngineType.fromDockerImageName(imageName);
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryActionDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryActionDTO.java
deleted file mode 100644
index 9b4ea75..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryActionDTO.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-public class ExploratoryActionDTO<T extends ExploratoryActionDTO<?>> extends ExploratoryBaseDTO<T> {
-    @JsonProperty("notebook_instance_name")
-    private String notebookInstanceName;
-
-	@JsonProperty("reupload_key_required")
-	private boolean reuploadKeyRequired;
-
-
-	public boolean isReuploadKeyRequired() {
-		return reuploadKeyRequired;
-	}
-
-	public void setReuploadKeyRequired(boolean reuploadKeyRequired) {
-		this.reuploadKeyRequired = reuploadKeyRequired;
-	}
-
-	@SuppressWarnings("unchecked")
-	public T withReuploadKeyRequired(boolean reuploadKeyRequired) {
-		setReuploadKeyRequired(reuploadKeyRequired);
-		return (T) this;
-	}
-
-	public String getNotebookInstanceName() {
-        return notebookInstanceName;
-    }
-
-    public void setNotebookInstanceName(String notebookInstanceName) {
-        this.notebookInstanceName = notebookInstanceName;
-    }
-
-    @SuppressWarnings("unchecked")
-    public T withNotebookInstanceName(String notebookInstanceName) {
-        setNotebookInstanceName(notebookInstanceName);
-        return (T) this;
-    }
-
-    @Override
-    public MoreObjects.ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-				.add("notebookInstanceName", notebookInstanceName);
-    }
-
-    @Override
-    public String toString() {
-        return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryBaseDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryBaseDTO.java
deleted file mode 100644
index 7942f68..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryBaseDTO.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.epam.dlab.dto.ResourceEnvBaseDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-public class ExploratoryBaseDTO<T extends ExploratoryBaseDTO<?>> extends ResourceEnvBaseDTO<T> {
-	@SuppressWarnings("unchecked")
-	private final T self = (T) this;
-	@JsonProperty("notebook_image")
-	private String notebookImage;
-	@JsonProperty("project_name")
-	private String project;
-	@JsonProperty("endpoint_name")
-	private String endpoint;
-
-	public String getNotebookImage() {
-		return notebookImage;
-	}
-
-	public void setNotebookImage(String notebookImage) {
-		this.notebookImage = notebookImage;
-	}
-
-	public T withNotebookImage(String notebookImage) {
-		setNotebookImage(notebookImage);
-		return self;
-	}
-
-	public T withProject(String project) {
-		setProject(project);
-		return self;
-	}
-	public T withEndpoint(String endpoint) {
-		setEndpoint(endpoint);
-		return self;
-	}
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("notebookImage", notebookImage);
-	}
-
-	public String getProject() {
-		return project;
-	}
-
-	public void setProject(String project) {
-		this.project = project;
-	}
-
-	public String getEndpoint() {
-		return endpoint;
-	}
-
-	public void setEndpoint(String endpoint) {
-		this.endpoint = endpoint;
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryCheckInactivityAction.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryCheckInactivityAction.java
deleted file mode 100644
index 28b6e66..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryCheckInactivityAction.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-public class ExploratoryCheckInactivityAction extends ExploratoryActionDTO<ExploratoryCheckInactivityAction> {
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryCreateDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryCreateDTO.java
deleted file mode 100644
index 557be36..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryCreateDTO.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import java.util.List;
-import java.util.Map;
-
-public class ExploratoryCreateDTO<T extends ExploratoryCreateDTO<?>> extends ExploratoryBaseDTO<T> {
-
-	@SuppressWarnings("unchecked")
-	private final T self = (T) this;
-
-	@JsonProperty("git_creds")
-	private List<ExploratoryGitCreds> gitCreds;
-	@JsonProperty("notebook_image_name")
-	private String imageName;
-	@JsonProperty("spark_configurations")
-	private List<ClusterConfig> clusterConfig;
-	@JsonProperty("tags")
-	private Map<String, String> tags;
-	@JsonProperty("endpoint_name")
-	private String endpoint;
-	@JsonProperty("conf_shared_image_enabled")
-	private String sharedImageEnabled;
-
-	/**
-	 * Return the list of GIT credentials.
-	 */
-	public List<ExploratoryGitCreds> getGitCreds() {
-		return gitCreds;
-	}
-
-	/**
-	 * Set the list of GIT credentials.
-	 */
-	public void setGitCreds(List<ExploratoryGitCreds> gitCreds) {
-		this.gitCreds = gitCreds;
-	}
-
-	/**
-	 * Set the list of GIT credentials and return this object.
-	 */
-	public T withGitCreds(List<ExploratoryGitCreds> gitCreds) {
-		setGitCreds(gitCreds);
-		return self;
-	}
-
-	/**
-	 * Set the image name and return this object.
-	 */
-	public T withImageName(String imageName) {
-		setImageName(imageName);
-		return self;
-	}
-
-	public T withTags(Map<String, String> tags) {
-		this.tags = tags;
-		return self;
-	}
-
-	@Override
-	public T withEndpoint(String endpoint) {
-		this.endpoint = endpoint;
-		return self;
-	}
-
-	public T withSharedImageEnabled(String sharedImageEnabled) {
-		this.sharedImageEnabled = sharedImageEnabled;
-		return self;
-	}
-
-	public String getImageName() {
-		return imageName;
-	}
-
-	public void setImageName(String imageName) {
-		this.imageName = imageName;
-	}
-
-	public T withClusterConfig(List<ClusterConfig> config) {
-		this.clusterConfig = config;
-		return self;
-	}
-
-	@Override
-	public String getEndpoint() {
-		return endpoint;
-	}
-
-	@Override
-	public void setEndpoint(String endpoint) {
-		this.endpoint = endpoint;
-	}
-
-	public String getSharedImageEnabled() {
-		return sharedImageEnabled;
-	}
-
-	public void setSharedImageEnabled(String sharedImageEnabled) {
-		this.sharedImageEnabled = sharedImageEnabled;
-	}
-
-	public List<ClusterConfig> getClusterConfig() {
-		return clusterConfig;
-	}
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("gitCreds", gitCreds)
-				.add("imageName", imageName);
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryGitCreds.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryGitCreds.java
deleted file mode 100644
index 0211ac5..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryGitCreds.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import javax.annotation.Nullable;
-import javax.validation.constraints.NotNull;
-
-/**
- * Describe GIT credentials.
- */
-public class ExploratoryGitCreds implements Comparable<ExploratoryGitCreds> {
-
-	@NotNull
-	@JsonProperty
-	private String hostname;
-
-	@NotNull
-	@JsonProperty
-	private String username;
-
-	@NotNull
-	@JsonProperty
-	private String email;
-
-	@NotNull
-	@JsonProperty
-	private String login;
-
-	@JsonProperty
-	private String password;
-
-	/**
-	 * Return the name of host.
-	 */
-	public String getHostname() {
-		return hostname;
-	}
-
-	/**
-	 * Set the name of host.
-	 */
-	public void setHostname(String hostname) {
-		this.hostname = hostname;
-	}
-
-	/**
-	 * Set the name of host.
-	 */
-	public ExploratoryGitCreds withHostname(String hostname) {
-		setHostname(hostname);
-		return this;
-	}
-
-	/**
-	 * Return the name of user.
-	 */
-	public String getUsername() {
-		return username;
-	}
-
-	/**
-	 * Set the name of user.
-	 */
-	public void setUsername(String username) {
-		this.username = username;
-	}
-
-	/**
-	 * Set the name of user.
-	 */
-	public ExploratoryGitCreds withUsername(String username) {
-		setUsername(username);
-		return this;
-	}
-
-	/**
-	 * Return the email.
-	 */
-	public String getEmail() {
-		return email;
-	}
-
-	/**
-	 * Set the email.
-	 */
-	public void setEmail(String email) {
-		this.email = email;
-	}
-
-	/**
-	 * Set the email.
-	 */
-	public ExploratoryGitCreds withEmail(String email) {
-		setEmail(email);
-		return this;
-	}
-
-	/**
-	 * Return the login.
-	 */
-	public String getLogin() {
-		return login;
-	}
-
-	/**
-	 * Set the login.
-	 */
-	public void setLogin(String login) {
-		this.login = login;
-	}
-
-	/**
-	 * Set the login.
-	 */
-	public ExploratoryGitCreds withLogin(String login) {
-		setLogin(login);
-		return this;
-	}
-
-	/**
-	 * Return the password.
-	 */
-	public String getPassword() {
-		return password;
-	}
-
-	/**
-	 * Set the password.
-	 */
-	public void setPassword(String password) {
-		this.password = password;
-	}
-
-	/**
-	 * Set the password.
-	 */
-	public ExploratoryGitCreds withPassword(String password) {
-		setPassword(password);
-		return this;
-	}
-
-	@Override
-	public int compareTo(@Nullable ExploratoryGitCreds obj) {
-		if (obj == null) {
-			return 1;
-		}
-		return this.hostname.compareToIgnoreCase(obj.hostname);
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj) {
-			return true;
-		}
-		return (obj instanceof ExploratoryGitCreds && (this.compareTo((ExploratoryGitCreds) obj) == 0));
-
-	}
-
-	@Override
-	public int hashCode() {
-		return getHostname() != null ? getHostname().hashCode() : 0;
-	}
-
-	@Override
-	public String toString() {
-		return "ExploratoryGitCreds{" +
-				"hostname='" + hostname + '\'' +
-				", username='" + username + '\'' +
-				", email='" + email + '\'' +
-				", login='" + login + '\'' +
-				", password='" + "***" + '\'' +
-				'}';
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryGitCredsDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryGitCredsDTO.java
deleted file mode 100644
index 6ba903d..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryGitCredsDTO.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import java.util.Collections;
-import java.util.List;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-/** Stores info about the GIT credentials. 
- * */
-public class ExploratoryGitCredsDTO {
-    @JsonProperty("git_creds")
-    private List<ExploratoryGitCreds> gitCreds;
-
-    /** Return the list of GIT credentials.
-     */
-    public List<ExploratoryGitCreds> getGitCreds() {
-        return gitCreds;
-    }
-
-    /** Set the list of GIT credentials and check the unique for host names.
-     */
-    public void setGitCreds(List<ExploratoryGitCreds> gitCreds) {
-    	if (gitCreds != null) {
-    		Collections.sort(gitCreds);
-    		for (int i = 1; i < gitCreds.size(); i++) {
-				if (gitCreds.get(i).equals(gitCreds.get(i - 1))) {
-					throw new IllegalArgumentException("Duplicate found for host name in git credentials: " + gitCreds.get(i).getHostname());
-				}
-			}
-    	}
-        this.gitCreds = gitCreds;
-    }
-
-    @Override
-    public String toString() {
-    	return MoreObjects.toStringHelper(this)
-                .add("gitCreds", gitCreds)
-    			.toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryGitCredsUpdateDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryGitCredsUpdateDTO.java
deleted file mode 100644
index 86536f0..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryGitCredsUpdateDTO.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import java.util.List;
-
-/** Store GIT credentials which should be updated on exploratory.
- */
-public class ExploratoryGitCredsUpdateDTO extends ExploratoryActionDTO<ExploratoryGitCredsUpdateDTO> {
-    @JsonProperty("git_creds")
-    private List<ExploratoryGitCreds> gitCreds;
-
-    /** Return the list of GIT credentials.
-     */
-    public List<ExploratoryGitCreds> getGitCreds() {
-        return gitCreds;
-    }
-
-    /** Set the list of GIT credentials.
-     */
-    public void setGitCreds(List<ExploratoryGitCreds> gitCreds) {
-        this.gitCreds = gitCreds;
-    }
-
-    /** Set the list of GIT credentials and return this object.
-     */
-    public ExploratoryGitCredsUpdateDTO withGitCreds(List<ExploratoryGitCreds> gitCreds) {
-        setGitCreds(gitCreds);
-        return this;
-    }
-
-
-    @Override
-    public ToStringHelper toStringHelper(Object self) {
-            return super.toStringHelper(self)
-                    .add("gitCreds", gitCreds);
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryImageDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryImageDTO.java
deleted file mode 100644
index f4cffa3..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryImageDTO.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-import lombok.Data;
-
-import java.util.Map;
-
-@Data
-public class ExploratoryImageDTO extends ExploratoryActionDTO<ExploratoryImageDTO> {
-
-	@JsonProperty("notebook_image_name")
-	private String imageName;
-
-	@JsonProperty("tags")
-	private Map<String, String> tags;
-	@JsonProperty("endpoint_name")
-	private String endpoint;
-	@JsonProperty("conf_shared_image_enabled")
-	private String sharedImageEnabled;
-
-	public ExploratoryImageDTO withImageName(String imageName) {
-		this.imageName = imageName;
-		return this;
-	}
-
-	public ExploratoryImageDTO withTags(Map<String, String> tags) {
-		this.tags = tags;
-		return this;
-	}
-
-	@Override
-	public ExploratoryImageDTO withEndpoint(String endpoint) {
-		this.endpoint = endpoint;
-		return this;
-	}
-
-	public ExploratoryImageDTO withSharedImageEnabled(String sharedImageEnabled) {
-		this.sharedImageEnabled = sharedImageEnabled;
-		return this;
-	}
-
-	@Override
-	public MoreObjects.ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("imageName", imageName);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryReconfigureSparkClusterActionDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryReconfigureSparkClusterActionDTO.java
deleted file mode 100644
index 3a7f6ab..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryReconfigureSparkClusterActionDTO.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import java.util.List;
-
-public class ExploratoryReconfigureSparkClusterActionDTO extends ExploratoryActionDTO<ExploratoryReconfigureSparkClusterActionDTO> {
-
-    @JsonProperty("spark_configurations")
-    private List<ClusterConfig> config;
-    @JsonProperty("azure_user_refresh_token")
-    private String azureUserRefreshToken;
-
-    public ExploratoryReconfigureSparkClusterActionDTO withConfig(List<ClusterConfig> config) {
-        this.config = config;
-        return this;
-    }
-
-    public ExploratoryReconfigureSparkClusterActionDTO withAzureUserRefreshToken(String azureUserRefreshToken) {
-        this.azureUserRefreshToken = azureUserRefreshToken;
-        return this;
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryStatusDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryStatusDTO.java
deleted file mode 100644
index ac2c9ed..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryStatusDTO.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.epam.dlab.dto.ResourceURL;
-import com.epam.dlab.dto.StatusEnvBaseDTO;
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import java.util.Date;
-import java.util.List;
-
-public class ExploratoryStatusDTO extends StatusEnvBaseDTO<ExploratoryStatusDTO> {
-	@JsonProperty("exploratory_url")
-	private List<ResourceURL> resourceUrl;
-	@JsonProperty("exploratory_user")
-	private String exploratoryUser;
-	@JsonProperty("exploratory_pass")
-	private String exploratoryPassword;
-	@JsonProperty("private_ip")
-	private String privateIp;
-	@JsonProperty("last_activity")
-	private Date lastActivity;
-	@JsonProperty
-	private List<ClusterConfig> config;
-
-	public String getPrivateIp() {
-		return privateIp;
-	}
-
-	public void setPrivateIp(String privateIp) {
-		this.privateIp = privateIp;
-	}
-
-	public ExploratoryStatusDTO withPrivateIp(String privateIp) {
-		setPrivateIp(privateIp);
-		return this;
-	}
-
-	public List<ResourceURL> getResourceUrl() {
-		return resourceUrl;
-	}
-
-	public void setResourceUrl(List<ResourceURL> resourceUrl) {
-		this.resourceUrl = resourceUrl;
-	}
-
-	public ExploratoryStatusDTO withExploratoryUrl(List<ResourceURL> resourceUrl) {
-		setResourceUrl(resourceUrl);
-		return this;
-	}
-
-	public String getExploratoryUser() {
-		return exploratoryUser;
-	}
-
-	public void setExploratoryUser(String exploratoryUser) {
-		this.exploratoryUser = exploratoryUser;
-	}
-
-	public ExploratoryStatusDTO withExploratoryUser(String exploratoryUser) {
-		setExploratoryUser(exploratoryUser);
-		return this;
-	}
-
-	public String getExploratoryPassword() {
-		return exploratoryPassword;
-	}
-
-	public void setExploratoryPassword(String exploratoryPassword) {
-		this.exploratoryPassword = exploratoryPassword;
-	}
-
-	public ExploratoryStatusDTO withExploratoryPassword(String exploratoryPassword) {
-		setExploratoryPassword(exploratoryPassword);
-		return this;
-	}
-
-	public ExploratoryStatusDTO withConfig(List<ClusterConfig> config) {
-		this.config = config;
-		return this;
-	}
-
-	public List<ClusterConfig> getConfig() {
-		return config;
-	}
-
-	public ExploratoryStatusDTO withLastActivity(Date lastActivity) {
-		this.lastActivity = lastActivity;
-		return this;
-	}
-
-	public Date getLastActivity() {
-		return lastActivity;
-	}
-
-	@Override
-	public ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("exploratoryUrl", resourceUrl)
-				.add("exploratoryUser", exploratoryUser)
-				.add("exploratoryPassword", exploratoryPassword)
-				.add("config", config);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ImageCreateStatusDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ImageCreateStatusDTO.java
deleted file mode 100644
index 44556a7..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ImageCreateStatusDTO.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.epam.dlab.dto.StatusBaseDTO;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.ToString;
-
-@Data
-public class ImageCreateStatusDTO extends StatusBaseDTO<ImageCreateStatusDTO> {
-
-	private ImageCreateDTO imageCreateDTO;
-	private String name;
-	private String exploratoryName;
-	private String project;
-	private String endpoint;
-
-	public ImageCreateStatusDTO withImageCreateDto(ImageCreateDTO imageCreateDto) {
-		setImageCreateDTO(imageCreateDto);
-		return this;
-	}
-
-	public ImageCreateStatusDTO withoutImageCreateDto() {
-		setImageCreateDTO(new ImageCreateDTO());
-		return this;
-	}
-
-	@Data
-	@ToString
-	@JsonIgnoreProperties(ignoreUnknown = true)
-	@NoArgsConstructor
-	public static class ImageCreateDTO {
-		private String externalName;
-		private String fullName;
-		private String user;
-		private String application;
-		private ImageStatus status;
-		private String ip;
-
-		@JsonCreator
-		public ImageCreateDTO(@JsonProperty("notebook_image_name") String externalName,
-							  @JsonProperty("full_image_name") String fullName,
-							  @JsonProperty("user_name") String user, @JsonProperty("application") String application,
-							  @JsonProperty("status") ImageStatus status, @JsonProperty("ip") String ip) {
-			this.externalName = externalName;
-			this.fullName = fullName;
-			this.user = user;
-			this.application = application;
-			this.status = status;
-			this.ip = ip;
-		}
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ImageStatus.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ImageStatus.java
deleted file mode 100644
index b25a40c..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ImageStatus.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-
-import java.util.Arrays;
-
-public enum ImageStatus {
-	CREATING,
-	CREATED,
-	FAILED;
-
-	@JsonCreator
-	public static ImageStatus fromValue(final String status) {
-		return Arrays.stream(ImageStatus.values())
-				.filter(s -> s.name().equalsIgnoreCase(status))
-				.findAny()
-				.orElseThrow(() -> new IllegalArgumentException(String.format("Wrong value for image status: %s",
-						status)));
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibInstallDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibInstallDTO.java
deleted file mode 100644
index 1d670a9..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibInstallDTO.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.util.List;
-
-/**
- * Stores info about libraries.
- */
-@Data
-@NoArgsConstructor
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class LibInstallDTO {
-	@JsonProperty
-	private String group;
-
-	@JsonProperty
-	private String name;
-
-	@JsonProperty
-	private String version;
-
-	@JsonProperty
-	private String status;
-
-	@JsonProperty("error_message")
-	private String errorMessage;
-
-	@JsonProperty
-	private boolean override;
-
-	@JsonProperty("available_versions")
-	private List<String> availableVersions;
-
-	@JsonProperty("add_pkgs")
-	private List<String> addedPackages;
-
-	public LibInstallDTO(String group, String name, String version) {
-		this.group = group;
-		this.name = name;
-		this.version = version;
-	}
-
-	public LibInstallDTO withName(String name) {
-		setName(name);
-		return this;
-	}
-
-	public LibInstallDTO withStatus(String status) {
-		setStatus(status);
-		return this;
-	}
-
-	public LibInstallDTO withErrorMessage(String errorMessage) {
-		setErrorMessage(errorMessage);
-		return this;
-	}
-
-	public LibInstallDTO withAddedPackages(List<String> addedPackages) {
-		setAddedPackages(addedPackages);
-		return this;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibInstallStatusDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibInstallStatusDTO.java
deleted file mode 100644
index e78847c..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibInstallStatusDTO.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.epam.dlab.dto.StatusEnvBaseDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.util.List;
-
-@Getter
-@Setter
-public class LibInstallStatusDTO extends StatusEnvBaseDTO<LibInstallStatusDTO> {
-    @JsonProperty
-    private List<LibInstallDTO> libs;
-
-    @JsonProperty
-    private String computationalName;
-
-
-    public LibInstallStatusDTO withLibs(List<LibInstallDTO> libs) {
-        setLibs(libs);
-        return this;
-    }
-
-    public LibInstallStatusDTO withComputationalName(String computationalName) {
-        setComputationalName(computationalName);
-        return this;
-    }
-
-    @Override
-    public ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("libs", libs)
-                .add("computationalName", computationalName);
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibListStatusDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibListStatusDTO.java
deleted file mode 100644
index 17b5d3c..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibListStatusDTO.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.epam.dlab.dto.StatusBaseDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-import lombok.Getter;
-import lombok.Setter;
-
-/**
- * Stores the info about group libraries.
- */
-@Getter
-@Setter
-public class LibListStatusDTO extends StatusBaseDTO<LibListStatusDTO> {
-
-    @JsonProperty
-    private String libs;
-
-    @JsonProperty
-    private String group;
-
-    /**
-     * Set the list of libraries and return this object
-     */
-    public LibListStatusDTO withLibs(String libs) {
-        setLibs(libs);
-        return this;
-    }
-
-    /**
-     * Set the name of group and return this object
-     */
-    public LibListStatusDTO withGroup(String group) {
-        setGroup(group);
-        return this;
-    }
-
-    @Override
-    public MoreObjects.ToStringHelper toStringHelper(Object self) {
-        return MoreObjects.toStringHelper(self)
-                .add("group", group)
-                .add("libs", (libs != null) ? "..." : null);
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibStatus.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibStatus.java
deleted file mode 100644
index 69197a1..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibStatus.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-
-/**
- * Statuses for the libraries.
- */
-public enum LibStatus {
-	INSTALLING,
-	INSTALLED,
-	INVALID_VERSION,
-	INVALID_NAME,
-	INSTALLATION_ERROR;
-
-	@JsonCreator
-	public static LibStatus of(String status) {
-		if (status != null) {
-			for (LibStatus uis : LibStatus.values()) {
-				if (status.equalsIgnoreCase(uis.toString())) {
-					return uis;
-				}
-			}
-		}
-		return null;
-	}
-
-	@Override
-	public String toString() {
-		return super.toString().toLowerCase();
-	}
-}
\ No newline at end of file
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibraryInstallDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibraryInstallDTO.java
deleted file mode 100644
index 28cac77..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/LibraryInstallDTO.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.dto.exploratory;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-import java.util.List;
-
-/**
- * Store info about libraries which user should be installed.
- */
-@Getter
-@Setter
-@ToString(callSuper = true)
-public class LibraryInstallDTO extends ExploratoryActionDTO<LibraryInstallDTO> {
-    @JsonProperty("libs")
-    private List<LibInstallDTO> libs;
-
-    @JsonProperty("computational_id")
-    private String computationalId;
-
-    @JsonProperty("computational_image")
-    private String computationalImage;
-
-    @JsonProperty("computational_name")
-    private String computationalName;
-
-    public LibraryInstallDTO withLibs(List<LibInstallDTO> libs) {
-        setLibs(libs);
-        return this;
-    }
-
-    public LibraryInstallDTO withComputationalId(String computationalId) {
-        setComputationalId(computationalId);
-        return this;
-    }
-
-    public LibraryInstallDTO withComputationalImage(String computationalImage) {
-        setComputationalImage(computationalImage);
-        return this;
-    }
-
-    public LibraryInstallDTO withComputationalName(String computationalName) {
-        setComputationalName(computationalName);
-        return this;
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/GcpCloudSettings.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/GcpCloudSettings.java
deleted file mode 100644
index c12c39a..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/GcpCloudSettings.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.dto.gcp;
-
-import com.epam.dlab.dto.base.CloudSettings;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.*;
-
-@Data
-@ToString(callSuper = true)
-@EqualsAndHashCode(callSuper = true)
-@NoArgsConstructor
-@Builder
-@AllArgsConstructor
-public class GcpCloudSettings extends CloudSettings {
-
-	@JsonProperty("gcp_iam_user")
-	private String gcpIamUser;
-	@JsonProperty("ldap_hostname")
-	protected String ldapHost;
-	@JsonProperty("ldap_dn")
-	protected String ldapDn;
-	@JsonProperty("ldap_ou")
-	protected String ldapOu;
-	@JsonProperty("ldap_service_username")
-	protected String ldapUser;
-	@JsonProperty("ldap_service_password")
-	protected String ldapPassword;
-	@JsonProperty("conf_os_family")
-	protected String os;
-	@JsonProperty("conf_cloud_provider")
-	protected String cloud;
-	@JsonProperty("conf_service_base_name")
-	protected String sbn;
-	@JsonProperty("conf_key_dir")
-	protected String confKeyDir;
-	@JsonProperty("gcp_project_id")
-	protected String projectId;
-	@JsonProperty("gcp_vpc_name")
-	protected String vpcName;
-	@JsonProperty("gcp_subnet_name")
-	protected String subnetName;
-	@JsonProperty("gcp_zone")
-	protected String zone;
-	@JsonProperty("gcp_region")
-	protected String region;
-	@JsonProperty("conf_image_enabled")
-	private String imageEnabled;
-	@JsonProperty("conf_stepcerts_enabled")
-	private String stepCertsEnabled;
-	@JsonProperty("conf_stepcerts_root_ca")
-	private String stepCertsRootCA;
-	@JsonProperty("conf_stepcerts_kid")
-	private String stepCertsKid;
-	@JsonProperty("conf_stepcerts_kid_password")
-	private String stepCertsKidPassword;
-	@JsonProperty("conf_stepcerts_ca_url")
-	private String stepCertsCAURL;
-	@JsonProperty("keycloak_auth_server_url")
-	private String keycloakAuthServerUrl;
-	@JsonProperty("keycloak_realm_name")
-	private String keycloakRealmName;
-	@JsonProperty("keycloak_user")
-	private String keycloakUser;
-	@JsonProperty("keycloak_user_password")
-	private String keycloakUserPassword;
-
-	@Override
-	@JsonIgnore
-	public String getIamUser() {
-		return gcpIamUser;
-	}
-}
\ No newline at end of file
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/auth/GcpOauth2AuthorizationCodeResponse.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/auth/GcpOauth2AuthorizationCodeResponse.java
deleted file mode 100644
index fbbdf83..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/auth/GcpOauth2AuthorizationCodeResponse.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.dto.gcp.auth;
-
-import lombok.Data;
-
-@Data
-public class GcpOauth2AuthorizationCodeResponse {
-	private final String code;
-	private final String state;
-	private final String errorMessage;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/ComputationalCreateGcp.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/ComputationalCreateGcp.java
deleted file mode 100644
index 1ab5698..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/ComputationalCreateGcp.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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.dto.gcp.computational;
-
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-public class ComputationalCreateGcp extends ComputationalBase<ComputationalCreateGcp> {
-    @JsonProperty("dataproc_master_count")
-    private String masterInstanceCount;
-    @JsonProperty("dataproc_slave_count")
-    private String slaveInstanceCount;
-    @JsonProperty("dataproc_master_instance_type")
-    private String masterInstanceType;
-    @JsonProperty("dataproc_slave_instance_type")
-    private String slaveInstanceType;
-    @JsonProperty("dataproc_preemptible_count")
-    private String preemptibleCount;
-    @JsonProperty("dataproc_version")
-    private String version;
-    @JsonProperty("conf_shared_image_enabled")
-    private String sharedImageEnabled;
-
-    public ComputationalCreateGcp withMasterInstanceCount(String masterInstanceCount) {
-        this.masterInstanceCount = masterInstanceCount;
-        return this;
-    }
-
-    public ComputationalCreateGcp withSlaveInstanceCount(String slaveInstanceCount) {
-        this.slaveInstanceCount = slaveInstanceCount;
-        return this;
-    }
-
-    public ComputationalCreateGcp withMasterInstanceType(String masterInstanceType) {
-        this.masterInstanceType = masterInstanceType;
-        return this;
-    }
-
-    public ComputationalCreateGcp withSlaveInstanceType(String slaveInstanceType) {
-        this.slaveInstanceType = slaveInstanceType;
-        return this;
-    }
-
-    public ComputationalCreateGcp withPreemptibleCount(String preemptibleCount) {
-        this.preemptibleCount = preemptibleCount;
-        return this;
-    }
-
-    public ComputationalCreateGcp withVersion(String version) {
-        this.version = version;
-        return this;
-    }
-
-    public String getSharedImageEnabled() {
-        return sharedImageEnabled;
-    }
-
-    public void setSharedImageEnabled(String sharedImageEnabled) {
-        this.sharedImageEnabled = sharedImageEnabled;
-    }
-
-    public ComputationalCreateGcp withSharedImageEnabled(String sharedImageEnabled) {
-        setSharedImageEnabled(sharedImageEnabled);
-        return this;
-    }
-
-    @Override
-    public MoreObjects.ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("version", version)
-                .add("masterInstanceType", masterInstanceType)
-                .add("slaveInstanceType", slaveInstanceType)
-                .add("masterInstanceCount", masterInstanceCount)
-                .add("slaveInstanceCount", slaveInstanceCount)
-                .add("preemptibleCount", preemptibleCount);
-    }
-
-    @Override
-    public String toString() {
-        return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/GcpComputationalResource.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/GcpComputationalResource.java
deleted file mode 100644
index b653818..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/GcpComputationalResource.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.dto.gcp.computational;
-
-import com.epam.dlab.dto.ResourceURL;
-import com.epam.dlab.dto.SchedulerJobDTO;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.ToString;
-
-import java.time.LocalDateTime;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Stores info about the user's computational resources for notebook.
- */
-@ToString(callSuper = true)
-@Getter
-@EqualsAndHashCode(callSuper = true)
-public class GcpComputationalResource extends UserComputationalResource {
-
-	@JsonProperty("instance_id")
-	private String instanceId;
-	@JsonProperty("master_node_shape")
-	private String masterShape;
-	@JsonProperty("slave_node_shape")
-	private String slaveShape;
-	@JsonProperty("total_slave_instance_number")
-	private String slaveNumber;
-	@JsonProperty("total_master_instance_number")
-	private String masterNumber;
-	@JsonProperty("total_preemptible_number")
-	private String preemptibleNumber;
-	@JsonProperty("dataproc_version")
-	private String version;
-
-	@Builder
-	public GcpComputationalResource(String computationalName, String computationalId, String imageName,
-									String templateName, String status, Date uptime,
-									SchedulerJobDTO schedulerJobData, boolean reuploadKeyRequired,
-									String instanceId, String masterShape, String slaveShape, String slaveNumber,
-									String masterNumber, String preemptibleNumber, String version,
-									List<ResourceURL> resourceURL, LocalDateTime lastActivity,
-									Map<String, String> tags, int totalInstanceCount) {
-		super(computationalName, computationalId, imageName, templateName, status, uptime, schedulerJobData,
-				reuploadKeyRequired, resourceURL, lastActivity, tags, totalInstanceCount);
-		this.instanceId = instanceId;
-		this.masterShape = masterShape;
-		this.slaveShape = slaveShape;
-		this.slaveNumber = slaveNumber;
-		this.masterNumber = masterNumber;
-		this.version = version;
-		this.preemptibleNumber = preemptibleNumber;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/GcpComputationalTerminateDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/GcpComputationalTerminateDTO.java
deleted file mode 100644
index 648b75f..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/GcpComputationalTerminateDTO.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.dto.gcp.computational;
-
-import com.epam.dlab.dto.computational.ComputationalTerminateDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.ToString;
-
-@Data
-@ToString(callSuper = true)
-public class GcpComputationalTerminateDTO extends ComputationalTerminateDTO {
-
-	@JsonProperty("dataproc_cluster_name")
-	private String clusterName;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/SparkComputationalCreateGcp.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/SparkComputationalCreateGcp.java
deleted file mode 100644
index e21881b..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/SparkComputationalCreateGcp.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.dto.gcp.computational;
-
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-import java.util.List;
-
-
-public class SparkComputationalCreateGcp extends ComputationalBase<SparkComputationalCreateGcp> {
-
-	@JsonProperty("dataengine_instance_count")
-	private String dataEngineInstanceCount;
-	@JsonProperty("gcp_dataengine_slave_size")
-	private String dataEngineSlaveSize;
-	@JsonProperty("gcp_dataengine_master_size")
-	private String dataEngineMasterSize;
-	@JsonProperty("spark_configurations")
-	private List<ClusterConfig> config;
-	@JsonProperty("conf_shared_image_enabled")
-	private String sharedImageEnabled;
-
-	public SparkComputationalCreateGcp withDataEngineInstanceCount(String dataEngineInstanceCount) {
-		this.dataEngineInstanceCount = dataEngineInstanceCount;
-		return this;
-	}
-
-	public SparkComputationalCreateGcp withDataEngineSlaveSize(String dataEngineSlaveSize) {
-		this.dataEngineSlaveSize = dataEngineSlaveSize;
-		return this;
-	}
-
-	public SparkComputationalCreateGcp withDataEngineMasterSize(String dataEngineMasterSize) {
-		this.dataEngineMasterSize = dataEngineMasterSize;
-		return this;
-	}
-
-	public SparkComputationalCreateGcp withConfig(List<ClusterConfig> config) {
-		this.config = config;
-		return this;
-	}
-
-	public SparkComputationalCreateGcp withSharedImageEnabled(String sharedImageEnabled) {
-		this.sharedImageEnabled = sharedImageEnabled;
-		return this;
-	}
-
-
-	@Override
-	public MoreObjects.ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("dataEngineInstanceCount", dataEngineInstanceCount)
-				.add("dataEngineSlaveSize", dataEngineSlaveSize)
-				.add("dataEngineMasterSize", dataEngineMasterSize);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/edge/EdgeCreateGcp.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/edge/EdgeCreateGcp.java
deleted file mode 100644
index 5de6acf..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/edge/EdgeCreateGcp.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.dto.gcp.edge;
-
-import com.epam.dlab.dto.ResourceSysBaseDTO;
-
-public class EdgeCreateGcp extends ResourceSysBaseDTO<EdgeCreateGcp> {
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/edge/EdgeInfoGcp.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/edge/EdgeInfoGcp.java
deleted file mode 100644
index b70fbfd..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/edge/EdgeInfoGcp.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.dto.gcp.edge;
-
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-@Getter
-@Setter
-@ToString(callSuper = true)
-@EqualsAndHashCode(callSuper = true)
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class EdgeInfoGcp extends EdgeInfo {
-    @JsonProperty("user_own_bucket_name")
-    private String userOwnBucketName;
-    @JsonProperty("shared_bucket_name")
-    private String sharedBucketName;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/exploratory/ExploratoryCreateGcp.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/exploratory/ExploratoryCreateGcp.java
deleted file mode 100644
index 2b123b8..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/exploratory/ExploratoryCreateGcp.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.dto.gcp.exploratory;
-
-import com.epam.dlab.dto.exploratory.ExploratoryCreateDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-public class ExploratoryCreateGcp extends ExploratoryCreateDTO<ExploratoryCreateGcp> {
-    @JsonProperty("gcp_notebook_instance_size")
-    private String notebookInstanceSize;
-
-    public String getNotebookInstanceSize() {
-        return notebookInstanceSize;
-    }
-
-    public void setNotebookInstanceSize(String notebookInstanceSize) {
-        this.notebookInstanceSize = notebookInstanceSize;
-    }
-
-    public ExploratoryCreateGcp withNotebookInstanceType(String notebookInstanceType) {
-        setNotebookInstanceSize(notebookInstanceType);
-        return this;
-    }
-
-    @Override
-    public MoreObjects.ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("notebookInstanceSize", notebookInstanceSize);
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/keyload/UploadFileGcp.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/keyload/UploadFileGcp.java
deleted file mode 100644
index 7204cae..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/keyload/UploadFileGcp.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.dto.gcp.keyload;
-
-import com.epam.dlab.dto.base.keyload.UploadFile;
-import com.epam.dlab.dto.gcp.edge.EdgeCreateGcp;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@Data
-@ToString(callSuper = true)
-@EqualsAndHashCode(callSuper = true)
-public class UploadFileGcp extends UploadFile {
-    @JsonProperty
-    private final EdgeCreateGcp edge;
-
-	@JsonCreator
-	public UploadFileGcp(@JsonProperty("edge") EdgeCreateGcp edge, @JsonProperty("content") String content) {
-        super(content);
-        this.edge = edge;
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ApplicationDto.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ApplicationDto.java
deleted file mode 100644
index 03bd04f..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ApplicationDto.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.dto.imagemetadata;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
-
-import java.util.Objects;
-
-public class ApplicationDto {
-    @JsonProperty("Version")
-    private String version;
-    @JsonProperty("Name")
-    private String name;
-
-    public ApplicationDto() {
-    }
-
-
-    public ApplicationDto(String version, String name) {
-        this.version = version;
-        this.name = name;
-    }
-
-    public String getVersion() {
-        return version;
-    }
-
-    public void setVersion(String version) {
-        this.version = version;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-
-        ApplicationDto that = (ApplicationDto) o;
-
-        if (version != null ? !version.equals(that.version) : that.version != null) {
-            return false;
-        }
-        return name != null ? name.equals(that.name) : that.name == null;
-
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(version, name);
-    }
-
-    @Override
-    public String toString() {
-        return ReflectionToStringBuilder.toString(this);
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ComputationalMetadataDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ComputationalMetadataDTO.java
deleted file mode 100644
index 30f648d..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ComputationalMetadataDTO.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.dto.imagemetadata;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.NoArgsConstructor;
-
-import java.util.List;
-import java.util.Map;
-
-@Data
-@NoArgsConstructor
-@EqualsAndHashCode(callSuper = false)
-public class ComputationalMetadataDTO extends ImageMetadataDTO {
-	@JsonProperty
-	protected String image;
-	@JsonProperty("template_name")
-	private String templateName;
-	@JsonProperty
-	private String description;
-	@JsonProperty("environment_type")
-	private String type;
-	@JsonProperty
-	private List<TemplateDTO> templates;
-	@JsonProperty("request_id")
-	private String requestId;
-	@JsonProperty(value = "computation_resources_shapes")
-	private Map<String, List<ComputationalResourceShapeDto>> computationResourceShapes;
-
-	public ComputationalMetadataDTO(String imageName) {
-		this.image = imageName;
-		setImageType(ImageType.COMPUTATIONAL);
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ComputationalResourceShapeDto.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ComputationalResourceShapeDto.java
deleted file mode 100644
index 361c552..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ComputationalResourceShapeDto.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.dto.imagemetadata;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
-
-public class ComputationalResourceShapeDto {
-	@JsonProperty("Type")
-	private String type;
-	@JsonProperty("Size")
-	private String size;
-	@JsonProperty("Description")
-	private String description;
-	@JsonProperty("Ram")
-	private String ram;
-	@JsonProperty("Cpu")
-	private int cpu;
-	@JsonProperty("Spot")
-	private boolean spot = false;
-
-	@JsonProperty("SpotPctPrice")
-	private int spotPctPrice = 70;
-
-
-	public ComputationalResourceShapeDto() {
-	}
-
-	public ComputationalResourceShapeDto(String type, String size, String description, String ram, int cpu) {
-		this.type = type;
-		this.size = size;
-		this.description = description;
-		this.ram = ram;
-		this.cpu = cpu;
-	}
-
-	public String getType() {
-		return type;
-	}
-
-	public void setType(String type) {
-		this.type = type;
-	}
-
-	public String getSize() {
-		return size;
-	}
-
-	public void setSize(String size) {
-		this.size = size;
-	}
-
-	public String getDescription() {
-		return description;
-	}
-
-	public void setDescription(String description) {
-		this.description = description;
-	}
-
-	public String getRam() {
-		return ram;
-	}
-
-	public void setRam(String ram) {
-		this.ram = ram;
-	}
-
-	public int getCpu() {
-		return cpu;
-	}
-
-	public void setCpu(int cpu) {
-		this.cpu = cpu;
-	}
-
-	public boolean isSpot() {
-		return spot;
-	}
-
-	public void setSpot(boolean spot) {
-		this.spot = spot;
-	}
-
-	public int getSpotPctPrice() {
-		return spotPctPrice;
-	}
-
-	public void setSpotPctPrice(int spotPctPrice) {
-		this.spotPctPrice = spotPctPrice;
-	}
-
-	@Override
-	public String toString() {
-		return ReflectionToStringBuilder.toString(this);
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ExploratoryEnvironmentVersion.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ExploratoryEnvironmentVersion.java
deleted file mode 100644
index 78bccee..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ExploratoryEnvironmentVersion.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.dto.imagemetadata;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
-
-public class ExploratoryEnvironmentVersion {
-    @JsonProperty("template_name")
-    private String templateName;
-    @JsonProperty
-    private String description;
-    @JsonProperty("environment_type")
-    private String type;
-    @JsonProperty("version")
-    private String version;
-    @JsonProperty("vendor")
-    private String vendor;
-
-    public ExploratoryEnvironmentVersion() {
-    }
-
-    public ExploratoryEnvironmentVersion(String templateName, String description, String type, String version,
-                                         String vendor) {
-        this.templateName = templateName;
-        this.description = description;
-        this.type = type;
-        this.version = version;
-        this.vendor = vendor;
-    }
-
-    public String getTemplateName() {
-        return templateName;
-    }
-
-    public void setTemplateName(String templateName) {
-        this.templateName = templateName;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    public String getType() {
-        return type;
-    }
-
-    public void setType(String type) {
-        this.type = type;
-    }
-
-    public String getVersion() {
-        return version;
-    }
-
-    public void setVersion(String version) {
-        this.version = version;
-    }
-
-    public String getVendor() {
-        return vendor;
-    }
-
-    public void setVendor(String vendor) {
-        this.vendor = vendor;
-    }
-
-    @Override
-    public String toString() {
-        return ReflectionToStringBuilder.toString(this);
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ExploratoryMetadataDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ExploratoryMetadataDTO.java
deleted file mode 100644
index dfa94a2..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ExploratoryMetadataDTO.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.dto.imagemetadata;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.NoArgsConstructor;
-
-import java.util.HashMap;
-import java.util.List;
-
-@Data
-@NoArgsConstructor
-@EqualsAndHashCode(callSuper = false)
-public class ExploratoryMetadataDTO extends ImageMetadataDTO {
-    @JsonProperty
-    protected String image;
-    @JsonProperty("exploratory_environment_versions")
-    private List<ExploratoryEnvironmentVersion> exploratoryEnvironmentVersions;
-    @JsonProperty("exploratory_environment_shapes")
-    private HashMap<String, List<ComputationalResourceShapeDto>> exploratoryEnvironmentShapes;
-    @JsonProperty("request_id")
-    private String requestId;
-
-    public ExploratoryMetadataDTO(String imageName) {
-        this.image = imageName;
-        setImageType(ImageType.EXPLORATORY);
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ImageMetadataDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ImageMetadataDTO.java
deleted file mode 100644
index 8fc7ba3..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ImageMetadataDTO.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.dto.imagemetadata;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
-
-/**
- * Common parent for metadata DTO. Holds type information during
- * runtime to make life easier when working with collection of metadatas or
- * filtering by type. Shouldnt be used to hold common attributes for upstream
- * hierarchy as it will requite type information to be serialized within json
- * which is not we really want.
- */
-public abstract class ImageMetadataDTO {
-    @JsonProperty("image_type")
-    private ImageType imageType;
-
-    public ImageType getImageType() {
-        return imageType;
-    }
-
-    public void setImageType(ImageType imageType) {
-        this.imageType = imageType;
-    }
-
-    public abstract void setImage(String image);
-
-    @Override
-    public String toString() {
-        return ReflectionToStringBuilder.toString(this);
-    }
-
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ImageType.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ImageType.java
deleted file mode 100644
index a030ee7..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/ImageType.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.dto.imagemetadata;
-
-public enum ImageType {
-    COMPUTATIONAL("computational"),
-    EXPLORATORY("exploratory");
-
-    private String type;
-
-    ImageType(String type) {
-        this.type = type;
-    }
-
-    public String getType() {
-        return type;
-    }
-    
-    public static ImageType of(String type) {
-        if (type != null) {
-            for (ImageType value : ImageType.values()) {
-                if (type.equalsIgnoreCase(value.toString())) {
-                    return value;
-                }
-            }
-        }
-        return null;
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/TemplateDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/TemplateDTO.java
deleted file mode 100644
index 92c6647..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/imagemetadata/TemplateDTO.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.dto.imagemetadata;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
-
-import java.util.List;
-import java.util.Objects;
-
-public class TemplateDTO {
-    @JsonProperty
-    private String version;
-    @JsonProperty
-    private List<ApplicationDto> applications;
-
-    public TemplateDTO() {
-    }
-
-    public TemplateDTO(String version) {
-        this.version = version;
-    }
-
-    public String getVersion() {
-        return version;
-    }
-
-    public void setVersion(String version) {
-        this.version = version;
-    }
-
-    public List<ApplicationDto> getApplications() {
-        return applications;
-    }
-
-    public void setApplications(List<ApplicationDto> applications) {
-        this.applications = applications;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-
-        TemplateDTO that = (TemplateDTO) o;
-
-        if (version != null ? !version.equals(that.version) : that.version != null) {
-            return false;
-        }
-        return applications != null ? applications.equals(that.applications) : that.applications == null;
-
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(version, applications);
-    }
-
-    @Override
-    public String toString() {
-        return ReflectionToStringBuilder.toString(this);
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/keyload/KeyLoadStatus.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/keyload/KeyLoadStatus.java
deleted file mode 100644
index 80429c4..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/keyload/KeyLoadStatus.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.dto.keyload;
-
-import javax.ws.rs.core.Response;
-import java.util.Arrays;
-
-public enum KeyLoadStatus {
-    NONE("none", null, Response.Status.NOT_FOUND),
-    NEW("new", null, Response.Status.ACCEPTED),
-    SUCCESS("success", "ok", Response.Status.OK),
-    ERROR("error", "err", Response.Status.INTERNAL_SERVER_ERROR);
-
-    private String status;
-    private String value;
-    private Response.Status httpStatus;
-
-    KeyLoadStatus(String status, String value, Response.Status httpStatus) {
-        this.status = status;
-        this.value = value;
-        this.httpStatus = httpStatus;
-    }
-
-    public String getStatus() {
-        return status;
-    }
-
-    public Response.Status getHttpStatus() {
-        return httpStatus;
-    }
-
-    public static boolean isSuccess(String value) {
-        return SUCCESS.value.equals(value);
-    }
-
-    public static String getStatus(boolean successed) {
-        return successed ? SUCCESS.status : ERROR.status;
-    }
-
-    public static KeyLoadStatus findByStatus(String status) {
-        return Arrays.stream(values()).reduce(NONE, (result, next) -> next.status.equalsIgnoreCase(status) ? next : result);
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/keyload/UserKeyDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/keyload/UserKeyDTO.java
deleted file mode 100644
index 5a4ecbe..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/keyload/UserKeyDTO.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.dto.keyload;
-
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class UserKeyDTO {
-    @JsonProperty
-    private String content;
-    @JsonProperty
-    private String status;
-
-    public String getContent() {
-        return content;
-    }
-
-    public void setContent(String content) {
-        this.content = content;
-    }
-
-    public UserKeyDTO withContent(String content) {
-        setContent(content);
-        return this;
-    }
-
-    public String getStatus() {
-        return status;
-    }
-
-    public void setStatus(String status) {
-        this.status = status;
-    }
-
-    public UserKeyDTO withStatus(String status) {
-        setStatus(status);
-        return this;
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/project/ProjectActionDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/project/ProjectActionDTO.java
deleted file mode 100644
index b8e4718..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/project/ProjectActionDTO.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.dto.project;
-
-import com.epam.dlab.dto.ResourceBaseDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-
-@Data
-@AllArgsConstructor
-public class ProjectActionDTO extends ResourceBaseDTO<ProjectActionDTO> {
-	@JsonProperty("project_name")
-	private final String name;
-	@JsonProperty("endpoint_name")
-	private final String endpoint;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/project/ProjectCreateDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/project/ProjectCreateDTO.java
deleted file mode 100644
index bae34a8..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/project/ProjectCreateDTO.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.dto.project;
-
-import com.epam.dlab.dto.ResourceBaseDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Data;
-
-@Data
-@Builder
-public class ProjectCreateDTO extends ResourceBaseDTO<ProjectCreateDTO> {
-	private final String key;
-	@JsonProperty("project_name")
-	private final String name;
-	@JsonProperty("project_tag")
-	private final String tag;
-	@JsonProperty("endpoint_name")
-	private final String endpoint;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/reuploadkey/ReuploadKeyCallbackDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/reuploadkey/ReuploadKeyCallbackDTO.java
deleted file mode 100644
index fa0f49b..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/reuploadkey/ReuploadKeyCallbackDTO.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.dto.reuploadkey;
-
-import com.epam.dlab.dto.ResourceSysBaseDTO;
-import com.epam.dlab.model.ResourceData;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-import lombok.Getter;
-
-@Getter
-public class ReuploadKeyCallbackDTO extends ResourceSysBaseDTO<ReuploadKeyCallbackDTO> {
-
-	@JsonProperty
-	private ResourceData resource;
-
-	@JsonProperty("resource_id")
-	private String resourceId;
-
-	@JsonProperty
-	private String id;
-
-
-	public ReuploadKeyCallbackDTO withResource(ResourceData resource) {
-		this.resource = resource;
-		return this;
-	}
-
-	public ReuploadKeyCallbackDTO withId(String id) {
-		this.id = id;
-		return this;
-	}
-
-	public ReuploadKeyCallbackDTO withResourceId(String resourceId) {
-		this.resourceId = resourceId;
-		return this;
-	}
-
-	@Override
-	public MoreObjects.ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("resource", resource)
-				.add("resource_id", resourceId)
-				.add("id", id);
-	}
-}
-
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/reuploadkey/ReuploadKeyDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/reuploadkey/ReuploadKeyDTO.java
deleted file mode 100644
index 7fd4e04..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/reuploadkey/ReuploadKeyDTO.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.dto.reuploadkey;
-
-import com.epam.dlab.dto.ResourceSysBaseDTO;
-import com.epam.dlab.model.ResourceData;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Getter;
-
-import java.util.List;
-
-@Getter
-public class ReuploadKeyDTO extends ResourceSysBaseDTO<ReuploadKeyDTO> {
-
-	@JsonProperty
-	private String content;
-
-	@JsonProperty
-	private List<ResourceData> resources;
-
-	@JsonProperty
-	private String id;
-
-
-	public ReuploadKeyDTO withContent(String content){
-		this.content = content;
-		return this;
-	}
-
-	public ReuploadKeyDTO withResources(List<ResourceData> resources) {
-		this.resources = resources;
-		return this;
-	}
-
-	public ReuploadKeyDTO withId(String id){
-		this.id = id;
-		return this;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/reuploadkey/ReuploadKeyStatus.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/reuploadkey/ReuploadKeyStatus.java
deleted file mode 100644
index 49203ba..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/reuploadkey/ReuploadKeyStatus.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.dto.reuploadkey;
-
-import java.util.Arrays;
-
-public enum ReuploadKeyStatus {
-
-	COMPLETED("N/A"), FAILED("N/A");
-
-	private String message;
-
-	ReuploadKeyStatus(String message) {
-		this.message = message;
-	}
-
-	public ReuploadKeyStatus withErrorMessage(String message) {
-		this.message = message;
-		return this;
-	}
-
-	public String message() {
-		return message;
-	}
-
-	public static ReuploadKeyStatus fromValue(String value) {
-		return Arrays.stream(values())
-				.filter(v -> v.name().equalsIgnoreCase(value))
-				.findAny()
-				.orElseThrow(() ->
-						new IllegalArgumentException("Wrong value for ReuploadKeyStatus: " + value));
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/reuploadkey/ReuploadKeyStatusDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/reuploadkey/ReuploadKeyStatusDTO.java
deleted file mode 100644
index 72a790a..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/reuploadkey/ReuploadKeyStatusDTO.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.dto.reuploadkey;
-
-import com.epam.dlab.dto.StatusBaseDTO;
-import com.google.common.base.MoreObjects;
-import lombok.Getter;
-
-@Getter
-public class ReuploadKeyStatusDTO extends StatusBaseDTO<ReuploadKeyStatusDTO> {
-
-	private ReuploadKeyCallbackDTO reuploadKeyCallbackDTO;
-	private ReuploadKeyStatus reuploadKeyStatus;
-
-
-	public ReuploadKeyStatusDTO withReuploadKeyCallbackDto(ReuploadKeyCallbackDTO reuploadKeyCallbackDTO) {
-		this.reuploadKeyCallbackDTO = reuploadKeyCallbackDTO;
-		return this;
-	}
-
-	public ReuploadKeyStatusDTO withReuploadKeyStatus(ReuploadKeyStatus status) {
-		this.reuploadKeyStatus = status;
-		return this;
-	}
-
-	@Override
-	public MoreObjects.ToStringHelper toStringHelper(Object self) {
-		return super.toStringHelper(self)
-				.add("reuploadKeyStatus", reuploadKeyStatus)
-				.add("reuploadKeyCallbackDTO", reuploadKeyCallbackDTO);
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvResource.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvResource.java
deleted file mode 100644
index 808581f..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvResource.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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.dto.status;
-
-import com.epam.dlab.model.ResourceType;
-import com.epam.dlab.util.mongo.IsoLocalDateTimeDeSerializer;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import lombok.NoArgsConstructor;
-
-import java.time.LocalDateTime;
-
-/**
- * Describe the resource (host, cluster, storage) for check status in Cloud.
- */
-@NoArgsConstructor
-public class EnvResource {
-	@JsonProperty
-	private String id;
-	@JsonProperty
-	private String status;
-	@JsonProperty
-	private String name;
-	@JsonProperty
-	private ResourceType resourceType;
-	@JsonProperty("project_name")
-	private String project;
-	@JsonProperty("endpoint_name")
-	private String endpoint;
-	@JsonDeserialize(using = IsoLocalDateTimeDeSerializer.class)
-	@JsonProperty
-	private LocalDateTime lastActivity;
-
-	public EnvResource(String id, String name, ResourceType resourceType, String project, String endpoint) {
-		this.id = id;
-		this.name = name;
-		this.resourceType = resourceType;
-		this.project = project;
-		this.endpoint = endpoint;
-	}
-
-	/**
-	 * Return the id of resource. instanceId for host, clusterId for cluster, path for storage.
-	 */
-	public String getId() {
-		return id;
-	}
-
-	/**
-	 * Set the id of resource. instanceId for host, clusterId for cluster, path for storage.
-	 */
-	public void setId(String id) {
-		this.id = id;
-	}
-
-	/**
-	 * Set the id of resource. instanceId for host, clusterId for cluster, path for storage.
-	 */
-	public EnvResource withId(String id) {
-		setId(id);
-		return this;
-	}
-
-	/**
-	 * Return the status of resource.
-	 */
-	public String getStatus() {
-		return status;
-	}
-
-	/**
-	 * Set the status of resource.
-	 */
-	public void setStatus(String status) {
-		this.status = status;
-	}
-
-	/**
-	 * Set the status of resource.
-	 */
-	public EnvResource withStatus(String status) {
-		setStatus(status);
-		return this;
-	}
-
-	public String getName() {
-		return name;
-	}
-
-	public ResourceType getResourceType() {
-		return resourceType;
-	}
-
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	public EnvResource withName(String name) {
-		setName(name);
-		return this;
-	}
-
-	public EnvResource withResourceType(ResourceType resourceType) {
-		setResourceType(resourceType);
-		return this;
-	}
-
-	public void setResourceType(ResourceType resourceType) {
-		this.resourceType = resourceType;
-	}
-
-	public LocalDateTime getLastActivity() {
-		return lastActivity;
-	}
-
-	public void setLastActivity(LocalDateTime lastActivity) {
-		this.lastActivity = lastActivity;
-	}
-
-	public EnvResource withLastActivity(LocalDateTime lastActivity) {
-		setLastActivity(lastActivity);
-		return this;
-	}
-
-	public String getEndpoint() {
-		return endpoint;
-	}
-
-	public ToStringHelper toStringHelper(Object self) {
-		return MoreObjects.toStringHelper(self)
-				.add("id", id)
-				.add("status", status)
-				.add("name", name)
-				.add("resourceType", resourceType)
-				.add("lastActivity", lastActivity);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvResourceList.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvResourceList.java
deleted file mode 100644
index 1deb175..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvResourceList.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.dto.status;
-
-import java.util.List;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-/** Describe the lists of resources (host, cluster, storage) for check status in Cloud.
- */
-public class EnvResourceList {
-    @JsonProperty("host")
-    private List<EnvResource> hostList;
-    @JsonProperty("cluster")
-    private List<EnvResource> clusterList;
-
-    /** Return the list of hosts. */
-    public List<EnvResource> getHostList() {
-        return hostList;
-    }
-
-    /** Set the list of hosts. */
-    public void setHostList(List<EnvResource> hostList) {
-        this.hostList = hostList;
-    }
-
-    /** Set the list of hosts. */
-    public EnvResourceList withHostList(List<EnvResource> hostList) {
-        setHostList(hostList);
-        return this;
-    }
-
-    /** Return the list of clusters. */
-    public List<EnvResource> getClusterList() {
-        return clusterList;
-    }
-
-    /** Set the list of clusters. */
-    public void setClusterList(List<EnvResource> clusterList) {
-        this.clusterList = clusterList;
-    }
-
-    /** Set the list of clusters. */
-    public EnvResourceList withClusterList(List<EnvResource> clusterList) {
-        setClusterList(clusterList);
-        return this;
-    }
-
-    public ToStringHelper toStringHelper(Object self) {
-    	return MoreObjects.toStringHelper(self)
-    	        .add("host", hostList)
-    	        .add("cluster", clusterList);
-    }
-    
-    @Override
-    public String toString() {
-    	return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvStatusDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvStatusDTO.java
deleted file mode 100644
index caf3cf3..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvStatusDTO.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.dto.status;
-
-import com.epam.dlab.dto.StatusBaseDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-/** Describe the lists of resources (host, cluster, storage) for check status in Cloud.
- */
-public class EnvStatusDTO extends StatusBaseDTO<EnvStatusDTO> {
-    @JsonProperty("edge_list_resources")
-    private EnvResourceList resourceList;
-    
-    /** Return the list of resources (hosts, clusters, storages). */
-    public EnvResourceList getResourceList() {
-        return resourceList;
-    }
-
-    /** Set the list of resources (hosts, clusters, storages). */
-    public void setResourceList(EnvResourceList resourceList) {
-        this.resourceList = resourceList;
-    }
-
-    /** Set the list of resources (hosts, clusters, storages). */
-	public EnvStatusDTO withResourceList(EnvResourceList resourceList) {
-        setResourceList(resourceList);
-        return this;
-    }
-
-    @Override
-    public ToStringHelper toStringHelper(Object self) {
-    	return super.toStringHelper(self)
-    	        .add("resourceList", resourceList);
-    }
-    
-    @Override
-    public String toString() {
-    	return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/ResourceData.java b/services/dlab-model/src/main/java/com/epam/dlab/model/ResourceData.java
deleted file mode 100644
index dc4526d..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/ResourceData.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.model;
-
-import lombok.AllArgsConstructor;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-
-@AllArgsConstructor
-@Getter
-@EqualsAndHashCode
-public class ResourceData {
-	private ResourceType resourceType;
-	private String resourceId;
-	private String exploratoryName;
-	private String computationalName;
-
-	public static ResourceData edgeResource(String resourceId) {
-		return new ResourceData(ResourceType.EDGE, resourceId, null, null);
-	}
-
-	public static ResourceData exploratoryResource(String resourceId, String exploratoryName) {
-		return new ResourceData(ResourceType.EXPLORATORY, resourceId, exploratoryName, null);
-	}
-
-	public static ResourceData computationalResource(String resourceId, String exploratoryName,
-													 String computationalName) {
-		return new ResourceData(ResourceType.COMPUTATIONAL, resourceId, exploratoryName, computationalName);
-	}
-
-	@Override
-	public String toString() {
-		StringBuilder sb = new StringBuilder();
-		if (resourceType == ResourceType.EDGE) {
-			return sb.append(resourceType.toString()).toString();
-		} else if (resourceType == ResourceType.EXPLORATORY) {
-			return sb.append(resourceType.toString()).append(" ").append(exploratoryName).toString();
-		} else if (resourceType == ResourceType.COMPUTATIONAL) {
-			return sb.append(resourceType.toString()).append(" ").append(computationalName)
-					.append(" affiliated with exploratory ").append(exploratoryName).toString();
-		} else return "";
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/ResourceEnum.java b/services/dlab-model/src/main/java/com/epam/dlab/model/ResourceEnum.java
deleted file mode 100644
index 4ee7d2c..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/ResourceEnum.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.model;
-
-import com.fasterxml.jackson.annotation.JsonValue;
-
-public enum ResourceEnum {
-	EDGE_NODE("edge node"),
-	NOTEBOOK("notebook");
-
-	private String name;
-
-	ResourceEnum(String name) {
-		this.name = name;
-	}
-
-	@JsonValue
-	@Override
-	public String toString() {
-		return name;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/ResourceType.java b/services/dlab-model/src/main/java/com/epam/dlab/model/ResourceType.java
deleted file mode 100644
index 2baf91d..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/ResourceType.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.model;
-
-public enum ResourceType {
-	COMPUTATIONAL("computational_resource"),
-	EDGE("edge_node"),
-	EXPLORATORY("exploratory");
-
-	private String name;
-
-	ResourceType(String name) {
-		this.name = name;
-	}
-
-	@Override
-	public String toString() {
-		return name;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/StringList.java b/services/dlab-model/src/main/java/com/epam/dlab/model/StringList.java
deleted file mode 100644
index be4ea8e..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/StringList.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.model;
-
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.WebApplicationException;
-import java.util.ArrayList;
-
-@Slf4j
-public class StringList extends ArrayList<String> {
-	public StringList(String s) {
-		super();
-
-		for (String v : s.split(",")) {
-			try {
-				add(v.trim());
-			} catch (Exception e) {
-				log.error("Something went wrong. Reason {}", e.getMessage(), e);
-				throw new WebApplicationException(400);
-			}
-		}
-		if (isEmpty())
-			throw new WebApplicationException(400);
-	}
-
-	public static String valueOf(String s) {
-		return s;
-	}
-}
\ No newline at end of file
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/aws/BillingResourceType.java b/services/dlab-model/src/main/java/com/epam/dlab/model/aws/BillingResourceType.java
deleted file mode 100644
index ce3803a..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/aws/BillingResourceType.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.model.aws;
-
-/** Billing resource types.
- */
-public enum BillingResourceType {
-	COMPUTER,
-	CLUSTER,
-	STORAGE,
-	STORAGE_EBS,
-	STORAGE_BUCKET,
-	IP_ADDRESS,
-	OTHER;
-	
-    public static BillingResourceType of(String string) {
-        if (string != null) {
-            for (BillingResourceType value : BillingResourceType.values()) {
-                if (string.equalsIgnoreCase(value.toString())) {
-                    return value;
-                }
-            }
-        }
-        return null;
-    }
-    
-    /** Return the category of resource.
-     * @param resourceType the type of resource.
-     */
-    public static String category(BillingResourceType resourceType) {
-    	switch (resourceType) {
-		case COMPUTER:
-			return "EC2";
-		case CLUSTER:
-			return "Compute";
-		case STORAGE:
-			return "Storage";
-		case STORAGE_EBS:
-			return "EBS";
-		case STORAGE_BUCKET:
-			return "S3";
-		case IP_ADDRESS:
-			return "Static";
-		default:
-			return "Other";
-		}
-	}
-    
-    /** Return the category of resource. */
-    public String category() {
-    	return category(this);
-    }
-
-    @Override
-    public String toString() {
-    	return super.toString().toUpperCase();
-    }
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/aws/ReportLine.java b/services/dlab-model/src/main/java/com/epam/dlab/model/aws/ReportLine.java
deleted file mode 100644
index ede4e23..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/aws/ReportLine.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * 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.model.aws;
-
-import com.epam.dlab.exceptions.ParseException;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import java.util.LinkedHashMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * The line of billing report.
- */
-public class ReportLine {
-	/** Patterns to calculate the type of resource in report line. */
-	private static final Pattern pInstancceId = Pattern.compile("^i-[a-z0-9]{17}$");
-	private static final Pattern pVolumeId = Pattern.compile("^vol-[a-z0-9]{17}$");
-	private static final Pattern pIpAddress = Pattern.compile("^[1-9][0-9]{0,2}\\.[1-9][0-9]{0,2}\\.[1-9][0-9]{0,2}\\.[1-9][0-9]{0,2}$");
-	private static final Pattern pClusterId = Pattern.compile("j-[A-Z0-9]{12,13}$");
-
-	public static final String FIELD_DLAB_ID = "dlab_id";
-	public static final String FIELD_USER_ID = "user";
-	public static final String FIELD_USAGE_DATE = "usage_date";
-	public static final String FIELD_PRODUCT = "product";
-	public static final String FIELD_USAGE_TYPE = "usage_type";
-	public static final String FIELD_USAGE = "usage";
-	public static final String FIELD_COST = "cost";
-	public static final String FIELD_CURRENCY_CODE = "currency_code";
-	public static final String FIELD_RESOURCE_TYPE = "resource_type";
-	public static final String FIELD_RESOURCE_ID = "resource_id";
-	public static final String FIELD_TAGS = "tags";
-	
-	@JsonProperty
-	private String dlabId;
-	
-	@JsonProperty
-	private String user;
-
-	@JsonProperty
-	private String usageDate;
-
-	@JsonProperty
-	private String usageIntervalEnd;
-
-	@JsonProperty
-	private String product;
-
-	@JsonProperty
-	private String usageType;
-
-	@JsonProperty
-	private double usage;
-	
-	@JsonProperty
-	private double cost;
-	
-	@JsonProperty
-	private String currencyCode;
-
-	@JsonProperty
-	private BillingResourceType resourceType;
-
-	@JsonProperty
-	private String resourceId;
-
-	@JsonProperty
-	private LinkedHashMap<String, String> tags;
-
-	
-	public String getDlabId() {
-		return dlabId;
-	}
-
-	public void setDlabId(String dlabId) {
-		this.dlabId = dlabId;
-	}
-
-	public String getUser() {
-		return user;
-	}
-
-	public void setUser(String user) {
-		this.user = user;
-	}
-
-	public String getUsageDate() {
-		return usageDate;
-	}
-
-	public void setUsageDate(String usageDate) {
-		this.usageDate = usageDate;
-	}
-
-	public String getProduct() {
-		return product;
-	}
-
-	public void setProduct(String product) {
-		this.product = product;
-	}
-
-	public String getUsageType() {
-		return usageType;
-	}
-
-	public void setUsageType(String usageType) {
-		this.usageType = usageType;
-	}
-
-	public double getUsage() {
-		return usage;
-	}
-
-	public void setUsage(double usage) {
-		this.usage = usage;
-	}
-
-	public double getCost() {
-		return cost;
-	}
-
-	public void setCost(double cost) {
-		this.cost = cost;
-	}
-
-	public String getCurrencyCode() {
-		return currencyCode;
-	}
-
-	public void setCurrencyCode(String currencyCode) {
-		this.currencyCode = currencyCode;
-	}
-
-	public String getResourceId() {
-		return resourceId;
-	}
-
-	public BillingResourceType getResourceType() {
-		return resourceType;
-	}
-
-	public LinkedHashMap<String, String> getTags() {
-		return tags;
-	}
-
-	public void setTags(LinkedHashMap<String, String> tags) {
-		this.tags = tags;
-	}
-	
-	/** Calculate and set the type of resource and resource id.
-	 * @throws ParseException */
-	public void setResourceTypeId(String resourceTypeId) throws ParseException {
-		if (product == null) {
-			throw new ParseException("Property product is not set");
-		}
-		
-		if ("Amazon Elastic MapReduce".equals(product) ||
-				   "Amazon Simple Queue Service".equals(product)) {
-			resourceType = BillingResourceType.CLUSTER;
-			Matcher m = pClusterId.matcher(resourceTypeId);
-			resourceId = (m.find() ? m.group() : null);
-		} else {
-			if ("Amazon Elastic Compute Cloud".equals(product)) {
-				if (pInstancceId.matcher(resourceTypeId).find()) {
-					resourceType = BillingResourceType.COMPUTER;
-				} else if(pVolumeId.matcher(resourceTypeId).find()) {
-					resourceType = BillingResourceType.STORAGE_EBS;
-				} else if (pIpAddress.matcher(resourceTypeId).find()) {
-					resourceType = BillingResourceType.IP_ADDRESS;
-				} else {
-					resourceType = BillingResourceType.COMPUTER;
-				}
-			} else if ("Amazon Simple Storage Service".equals(product)) {
-				resourceType = BillingResourceType.STORAGE_BUCKET;
-			} else {
-				resourceType = BillingResourceType.OTHER;
-			}
-			resourceId = resourceTypeId;
-		}
-	}
-
-
-	/** Returns a string representation of the object.
-	 * @param self the object to generate the string for (typically this), used only for its class name.
-	 */
-	public ToStringHelper toStringHelper(Object self) {
-		return MoreObjects.toStringHelper(self)
-				.add(FIELD_DLAB_ID, dlabId)
-				.add(FIELD_USER_ID, user)
-				.add(FIELD_USAGE_DATE, usageDate)
-				.add(FIELD_PRODUCT, product)
-				.add(FIELD_USAGE_TYPE, usageType)
-				.add(FIELD_USAGE, usage)
-				.add(FIELD_COST, cost)
-				.add(FIELD_CURRENCY_CODE, currencyCode)
-				.add(FIELD_RESOURCE_TYPE, resourceType)
-				.add(FIELD_RESOURCE_ID, resourceId)
-				.add(FIELD_TAGS, tags);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this)
-				.toString();
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/azure/AzureAuthFile.java b/services/dlab-model/src/main/java/com/epam/dlab/model/azure/AzureAuthFile.java
deleted file mode 100644
index 21b1bf2..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/azure/AzureAuthFile.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.model.azure;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Getter;
-import lombok.ToString;
-
-@Getter
-@ToString(exclude = {"clientSecret"})
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class AzureAuthFile {
-    @JsonProperty
-    private String clientId;
-    @JsonProperty
-    private String clientSecret;
-    @JsonProperty
-    private String tenantId;
-    @JsonProperty
-    private String subscriptionId;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/exploratory/Exploratory.java b/services/dlab-model/src/main/java/com/epam/dlab/model/exploratory/Exploratory.java
deleted file mode 100644
index 4b67f70..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/exploratory/Exploratory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.model.exploratory;
-
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import lombok.Builder;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-@Builder
-public class Exploratory {
-	private final String name;
-	private final String dockerImage;
-	private final String version;
-	private final String templateName;
-	private final String shape;
-	private final String imageName;
-	private final String endpoint;
-	private final String project;
-	private final String exploratoryTag;
-	private final List<ClusterConfig> clusterConfig;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/exploratory/Image.java b/services/dlab-model/src/main/java/com/epam/dlab/model/exploratory/Image.java
deleted file mode 100644
index c1a4f4a..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/exploratory/Image.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.model.exploratory;
-
-import com.epam.dlab.dto.exploratory.ImageStatus;
-import com.epam.dlab.model.library.Library;
-import lombok.Builder;
-import lombok.Data;
-
-import java.util.List;
-import java.util.Map;
-
-@Data
-@Builder
-public class Image {
-	private final String name;
-	private final String description;
-	private final ImageStatus status;
-	private final String exploratoryId;
-	private final String project;
-	private final String endpoint;
-	private final String user;
-	private final String fullName;
-	private final String externalName;
-	private final String application;
-	private final String dockerImage;
-	private final List<Library> libraries;
-	private final Map<String, List<Library>> computationalLibraries;
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/library/Library.java b/services/dlab-model/src/main/java/com/epam/dlab/model/library/Library.java
deleted file mode 100644
index f40521c..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/library/Library.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.model.library;
-
-import com.epam.dlab.dto.exploratory.LibStatus;
-import com.epam.dlab.model.ResourceType;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class Library {
-	private final String group;
-	private final String name;
-	private final String version;
-	private final LibStatus status;
-	@JsonProperty("error_message")
-	private final String errorMessage;
-	@JsonProperty("available_versions")
-	private List<String> availableVersions;
-	@JsonProperty("add_pkgs")
-	private List<String> addedPackages;
-	private String resourceName;
-	private ResourceType type;
-
-	public Library withType(ResourceType type) {
-		setType(type);
-		return this;
-	}
-
-	public Library withResourceName(String name) {
-		setResourceName(name);
-		return this;
-	}
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/scheduler/SchedulerJobData.java b/services/dlab-model/src/main/java/com/epam/dlab/model/scheduler/SchedulerJobData.java
deleted file mode 100644
index 222d684..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/scheduler/SchedulerJobData.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.model.scheduler;
-
-import com.epam.dlab.dto.SchedulerJobDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-@Data
-public class SchedulerJobData {
-
-	@JsonProperty
-	private final String user;
-
-	@JsonProperty("exploratory_name")
-	private final String exploratoryName;
-
-	@JsonProperty("computational_name")
-	private final String computationalName;
-
-    @JsonProperty
-    private final String project;
-
-	@JsonProperty("scheduler_data")
-	private final SchedulerJobDTO jobDTO;
-}
-
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/systeminfo/DiskInfo.java b/services/dlab-model/src/main/java/com/epam/dlab/model/systeminfo/DiskInfo.java
deleted file mode 100644
index 0a8527b..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/systeminfo/DiskInfo.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.model.systeminfo;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Getter;
-
-@Builder
-@Getter
-public class DiskInfo {
-
-	@JsonProperty
-	private String serialNumber;
-	@JsonProperty
-	private long usedByteSpace;
-	@JsonProperty
-	private long totalByteSpace;
-
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/systeminfo/MemoryInfo.java b/services/dlab-model/src/main/java/com/epam/dlab/model/systeminfo/MemoryInfo.java
deleted file mode 100644
index 1930386..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/systeminfo/MemoryInfo.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.model.systeminfo;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Getter;
-
-@Builder
-@Getter
-public class MemoryInfo {
-
-	@JsonProperty
-	private long availableMemory;
-	@JsonProperty
-	private long totalMemory;
-
-	private long swapTotal;
-	private long swapUsed;
-	private long pagesPageIn;
-	private long pagesPageOut;
-
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/systeminfo/OsInfo.java b/services/dlab-model/src/main/java/com/epam/dlab/model/systeminfo/OsInfo.java
deleted file mode 100644
index 533605c..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/systeminfo/OsInfo.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.model.systeminfo;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Getter;
-
-@Builder
-@Getter
-public class OsInfo {
-
-	@JsonProperty
-	private String manufacturer;
-	@JsonProperty
-	private String family;
-	@JsonProperty
-	private String version;
-	@JsonProperty
-	private String buildNumber;
-
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/systeminfo/ProcessorInfo.java b/services/dlab-model/src/main/java/com/epam/dlab/model/systeminfo/ProcessorInfo.java
deleted file mode 100644
index 735f814..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/systeminfo/ProcessorInfo.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.model.systeminfo;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Getter;
-
-@Builder
-@Getter
-public class ProcessorInfo {
-
-	private String model;
-	private String family;
-
-	@JsonProperty
-	private String name;
-
-	private String id;
-	private String vendor;
-	private int logicalCoreCount;
-	private int physicalCoreCount;
-	private boolean isCpu64Bit;
-
-	@JsonProperty
-	private double currentSystemLoad;
-	@JsonProperty
-	private double systemLoadAverage;
-
-}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/util/CloudSettingsDeserializer.java b/services/dlab-model/src/main/java/com/epam/dlab/util/CloudSettingsDeserializer.java
deleted file mode 100644
index 86d7468..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/util/CloudSettingsDeserializer.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.util;
-
-import com.epam.dlab.dto.aws.AwsCloudSettings;
-import com.epam.dlab.dto.azure.AzureCloudSettings;
-import com.epam.dlab.dto.base.CloudSettings;
-import com.epam.dlab.dto.gcp.GcpCloudSettings;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonNode;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-@Slf4j
-public class CloudSettingsDeserializer extends JsonDeserializer<CloudSettings> {
-	@Override
-	public CloudSettings deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
-		JsonNode jsonNode = p.readValueAsTree();
-
-		Map<String, String> mapJson = new HashMap<>();
-		for (Iterator<String> it = jsonNode.fieldNames(); it.hasNext(); ) {
-			String s = it.next();
-			mapJson.put(s, jsonNode.get(s).textValue());
-		}
-
-		try {
-			return createFromMap(detectCloudSettings(mapJson), mapJson);
-		} catch (IllegalAccessException e) {
-			log.error("Cannot deserialize object due to {}", e.getMessage(), e);
-			throw new IllegalArgumentException("Cannot deserialize cloud settings " + mapJson);
-		}
-	}
-
-	private CloudSettings detectCloudSettings(Map<String, String> properties) {
-		for (Map.Entry<String, String> entry : properties.entrySet()) {
-			if (entry.getKey().startsWith("aws")) {
-				return new AwsCloudSettings();
-			} else if (entry.getKey().startsWith("azure")) {
-				return new AzureCloudSettings();
-			} else if (entry.getKey().startsWith("gcp")) {
-				return new GcpCloudSettings();
-			}
-		}
-		throw new IllegalArgumentException("Unknown properties " + properties);
-	}
-
-	private <T extends CloudSettings> T createFromMap(T settings, Map<String, String> map) throws
-			IllegalAccessException {
-		for (Field field : settings.getClass().getDeclaredFields()) {
-			if (field.getAnnotation(JsonProperty.class) != null) {
-				String value = map.get(field.getAnnotation(JsonProperty.class).value());
-				if (value != null) {
-					field.setAccessible(true);
-					field.set(settings, value);
-
-				}
-			}
-		}
-
-		return settings;
-	}
-
-}
\ No newline at end of file
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/util/JsonGenerator.java b/services/dlab-model/src/main/java/com/epam/dlab/util/JsonGenerator.java
deleted file mode 100644
index 366fed9..0000000
--- a/services/dlab-model/src/main/java/com/epam/dlab/util/JsonGenerator.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.util;
-
-import com.epam.dlab.dto.ResourceBaseDTO;
-import com.epam.dlab.dto.base.CloudSettings;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonUnwrapped;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-public final class JsonGenerator {
-	private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
-			.setSerializationInclusion(JsonInclude.Include.NON_NULL)
-			.addMixIn(ResourceBaseDTO.class, CloudSettingsUnwrapping.class);
-
-	private JsonGenerator() {
-	}
-
-	public static String generateJson(ResourceBaseDTO<?> resourceBaseDTO) throws JsonProcessingException {
-		return generateJson(resourceBaseDTO, false);
-	}
-
-	private static String generateJson(ResourceBaseDTO<?> resourceBaseDTO, boolean pretty) throws
-            JsonProcessingException {
-		if (pretty) {
-			return OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(resourceBaseDTO);
-		} else {
-			return OBJECT_MAPPER.writeValueAsString(resourceBaseDTO);
-		}
-	}
-
-	private abstract static class CloudSettingsUnwrapping {
-		@JsonUnwrapped
-		private CloudSettings cloudSettings;
-	}
-}
diff --git a/services/dlab-model/src/test/java/com/epam/dlab/dto/status/EnvResourceDTOTest.java b/services/dlab-model/src/test/java/com/epam/dlab/dto/status/EnvResourceDTOTest.java
deleted file mode 100644
index 3017bb8..0000000
--- a/services/dlab-model/src/test/java/com/epam/dlab/dto/status/EnvResourceDTOTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.dto.status;
-
-import static org.junit.Assert.assertEquals;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.epam.dlab.dto.UserEnvironmentResources;
-import org.junit.Test;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-public class EnvResourceDTOTest {
-	
-	private static String getJsonString(Object object) throws JsonProcessingException {
-        ObjectMapper objectMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
-        return objectMapper.writeValueAsString(object);
-    }
-	
-	private static <T> T getJsonObject(String string, Class<T> objectType) throws IOException {
-        ObjectMapper objectMapper = new ObjectMapper();
-        return objectMapper.readValue(string, objectType);
-    }
-
-	@Test
-    public void serde() throws IOException {
-    	List<EnvResource> hosts1 = new ArrayList<EnvResource>();
-    	hosts1.add(new EnvResource().withId("1"));
-    	hosts1.add(new EnvResource().withId("2"));
-    	hosts1.add(new EnvResource().withId("3").withStatus("state3"));
-    	assertEquals(hosts1.get(0).getId(), "1");
-    	assertEquals(hosts1.get(2).getStatus(), "state3");
-    	
-    	List<EnvResource> clusters1 = new ArrayList<EnvResource>();
-    	clusters1.add(new EnvResource().withId("10"));
-    	clusters1.add(new EnvResource().withId("11"));
-    	assertEquals(clusters1.get(0).getId(), "10");
-    	
-    	EnvResourceList r1 = new EnvResourceList()
-    			.withHostList(hosts1).withClusterList(clusters1);
-    	assertEquals(r1.getHostList().get(1).getId(), "2");
-    	assertEquals(r1.getHostList().get(2).getId(), "3");
-    	assertEquals(r1.getClusterList().get(1).getId(), "11");
-    	
-    	UserEnvironmentResources rs1 = new UserEnvironmentResources()
-    			.withResourceList(r1);
-    	assertEquals(rs1.getResourceList().getHostList().get(0).getId(), "1");
-    	assertEquals(rs1.getResourceList().getClusterList().get(0).getId(), "10");
-    	
-    	String json1 = getJsonString(rs1);
-    	
-    	UserEnvironmentResources rs2 = getJsonObject(json1, UserEnvironmentResources.class);
-    	String json2 = getJsonString(rs2);
-    	assertEquals(rs1.getResourceList().getHostList().size(), rs2.getResourceList().getHostList().size());
-    	assertEquals(rs1.getResourceList().getClusterList().size(), rs2.getResourceList().getClusterList().size());
-    	
-    	assertEquals("Json SerDe error", json1, json2);
-    }
-}
diff --git a/services/dlab-model/src/test/java/com/epam/dlab/dto/status/EnvStatusDTOTest.java b/services/dlab-model/src/test/java/com/epam/dlab/dto/status/EnvStatusDTOTest.java
deleted file mode 100644
index c2e0ab6..0000000
--- a/services/dlab-model/src/test/java/com/epam/dlab/dto/status/EnvStatusDTOTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.dto.status;
-
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-
-public class EnvStatusDTOTest {
-
-	private static String getJsonString(Object object) throws JsonProcessingException {
-		ObjectMapper objectMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
-		return objectMapper.writeValueAsString(object);
-	}
-
-	private static <T> T getJsonObject(String string, Class<T> objectType) throws IOException {
-		ObjectMapper objectMapper = new ObjectMapper();
-		return objectMapper.readValue(string, objectType);
-	}
-
-	@Test
-	public void serde() throws IOException {
-		List<EnvResource> hosts1 = new ArrayList<EnvResource>();
-		hosts1.add(new EnvResource().withId("1"));
-		hosts1.add(new EnvResource().withId("2"));
-		hosts1.add(new EnvResource().withId("3").withStatus("state3"));
-		assertEquals(hosts1.get(0).getId(), "1");
-		assertEquals(hosts1.get(2).getStatus(), "state3");
-
-		List<EnvResource> clusters1 = new ArrayList<EnvResource>();
-		clusters1.add(new EnvResource().withId("10"));
-		clusters1.add(new EnvResource().withId("11"));
-		assertEquals(clusters1.get(0).getId(), "10");
-
-		EnvResourceList r1 = new EnvResourceList()
-				.withHostList(hosts1).withClusterList(clusters1);
-		assertEquals(r1.getHostList().get(1).getId(), "2");
-		assertEquals(r1.getHostList().get(2).getId(), "3");
-		assertEquals(r1.getClusterList().get(1).getId(), "11");
-
-		EnvStatusDTO rs1 = new EnvStatusDTO()
-				.withUser("user1")
-				.withUptime(new Date())
-				.withStatus(UserInstanceStatus.CREATED)
-				.withErrorMessage("errorMessage1")
-				.withResourceList(r1);
-		assertEquals(rs1.getResourceList().getHostList().get(0).getId(), "1");
-		assertEquals(rs1.getResourceList().getClusterList().get(0).getId(), "10");
-
-		String json1 = getJsonString(rs1);
-
-		EnvStatusDTO rs2 = getJsonObject(json1, EnvStatusDTO.class);
-		String json2 = getJsonString(rs2);
-		assertEquals(rs1.getUser(), rs2.getUser());
-		assertEquals(rs1.getUptime(), rs2.getUptime());
-		assertEquals(rs1.getStatus(), rs2.getStatus());
-		assertEquals(rs1.getErrorMessage(), rs2.getErrorMessage());
-		assertEquals(rs1.getResourceList().getHostList().size(), rs2.getResourceList().getHostList().size());
-		assertEquals(rs1.getResourceList().getClusterList().size(), rs2.getResourceList().getClusterList().size());
-
-		assertEquals("Json SerDe error", json1, json2);
-	}
-}
diff --git a/services/dlab-model/src/test/java/com/epam/dlab/util/JsonGeneratorTest.java b/services/dlab-model/src/test/java/com/epam/dlab/util/JsonGeneratorTest.java
deleted file mode 100644
index 55327ba..0000000
--- a/services/dlab-model/src/test/java/com/epam/dlab/util/JsonGeneratorTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.util;
-
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyDTO;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class JsonGeneratorTest {
-
-	@Test
-	public void generateJsonTest() throws JsonProcessingException {
-		ReuploadKeyDTO dto = new ReuploadKeyDTO();
-		dto.withContent("someContent").withId("someId").withEdgeUserName("edgeUserName").withServiceBaseName("SBN");
-		String actual = JsonGenerator.generateJson(dto);
-		String expected = "{\"@class\":\"com.epam.dlab.dto.reuploadkey.ReuploadKeyDTO\",\"content\":\"someContent\"," +
-				"\"id\":\"someId\",\"edge_user_name\":\"edgeUserName\",\"conf_service_base_name\":\"SBN\"}";
-		Assert.assertEquals(expected, actual);
-	}
-}
diff --git a/services/dlab-mongo-migration/pom.xml b/services/dlab-mongo-migration/pom.xml
deleted file mode 100644
index 1f7b38f..0000000
--- a/services/dlab-mongo-migration/pom.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<!--
-  ~ 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.
-  -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>com.epam.dlab</groupId>
-        <artifactId>dlab</artifactId>
-        <version>1.0</version>
-        <relativePath>../../pom.xml</relativePath>
-    </parent>
-
-    <artifactId>dlab-mongo-migration</artifactId>
-
-    <dependencies>
-        <dependency>
-            <groupId>com.github.mongobee</groupId>
-            <artifactId>mongobee</artifactId>
-            <version>0.13</version>
-        </dependency>
-    </dependencies>
-</project>
diff --git a/services/dlab-mongo-migration/src/main/java/com/epam/dlab/migration/DbMigration.java b/services/dlab-mongo-migration/src/main/java/com/epam/dlab/migration/DbMigration.java
deleted file mode 100644
index 492b2a7..0000000
--- a/services/dlab-mongo-migration/src/main/java/com/epam/dlab/migration/DbMigration.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.migration;
-
-@FunctionalInterface
-public interface DbMigration {
-
-	void migrate();
-}
diff --git a/services/dlab-mongo-migration/src/main/java/com/epam/dlab/migration/exception/DlabDbMigrationException.java b/services/dlab-mongo-migration/src/main/java/com/epam/dlab/migration/exception/DlabDbMigrationException.java
deleted file mode 100644
index 75034df..0000000
--- a/services/dlab-mongo-migration/src/main/java/com/epam/dlab/migration/exception/DlabDbMigrationException.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.migration.exception;
-
-public class DlabDbMigrationException extends RuntimeException {
-
-	public DlabDbMigrationException(String message, Throwable cause) {
-		super(message, cause);
-	}
-}
diff --git a/services/dlab-mongo-migration/src/main/java/com/epam/dlab/migration/mongo/DlabMongoMigration.java b/services/dlab-mongo-migration/src/main/java/com/epam/dlab/migration/mongo/DlabMongoMigration.java
deleted file mode 100644
index 36c6288..0000000
--- a/services/dlab-mongo-migration/src/main/java/com/epam/dlab/migration/mongo/DlabMongoMigration.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.migration.mongo;
-
-import com.epam.dlab.migration.DbMigration;
-import com.epam.dlab.migration.exception.DlabDbMigrationException;
-import com.epam.dlab.migration.mongo.changelog.DlabChangeLog;
-import com.github.mongobee.Mongobee;
-import com.github.mongobee.exception.MongobeeException;
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-public class DlabMongoMigration implements DbMigration {
-	private static final String MONGODB_URI_FORMAT = "mongodb://%s:%s@%s:%d/%s";
-	private final Mongobee runner;
-
-	public DlabMongoMigration(String host, int port, String user, String password, String db) {
-		runner = new Mongobee(String.format(MONGODB_URI_FORMAT, user, password, host, port, db));
-		runner.setDbName(db);
-		runner.setChangeLogsScanPackage(DlabChangeLog.class.getPackage().getName());
-	}
-
-	public void migrate() {
-		try {
-			runner.execute();
-		} catch (MongobeeException e) {
-			log.error("Mongo db migration failed: {}", e.getMessage());
-			throw new DlabDbMigrationException("Mongo db migration failed", e);
-		}
-	}
-}
diff --git a/services/dlab-mongo-migration/src/main/java/com/epam/dlab/migration/mongo/changelog/DlabChangeLog.java b/services/dlab-mongo-migration/src/main/java/com/epam/dlab/migration/mongo/changelog/DlabChangeLog.java
deleted file mode 100644
index c718378..0000000
--- a/services/dlab-mongo-migration/src/main/java/com/epam/dlab/migration/mongo/changelog/DlabChangeLog.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.migration.mongo.changelog;
-
-import com.github.mongobee.changeset.ChangeLog;
-import com.github.mongobee.changeset.ChangeSet;
-import com.mongodb.BasicDBObject;
-import com.mongodb.DB;
-import com.mongodb.DBCollection;
-import com.mongodb.DBObject;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.StreamSupport;
-
-@ChangeLog
-@Slf4j
-public class DlabChangeLog {
-
-	public static final String ID = "_id";
-
-	@ChangeSet(order = "001", id = "001", author = "bhliva")
-	public void migrateSchedulerFields(DB db) {
-		log.info("Replacing field days_repeat with start_days_repeat and stop_days_repeat");
-		final DBCollection userInstances = db.getCollection("userInstances");
-
-		StreamSupport.stream(userInstances.find().spliterator(), false)
-				.forEach(dbObject -> updateSchedulerFieldsForExploratory(userInstances, dbObject));
-		log.info("Replacing scheduler field days_repeat finished successfully");
-	}
-
-	@SuppressWarnings("unchecked")
-	private void updateSchedulerFieldsForExploratory(DBCollection userInstances, DBObject dbObject) {
-		updateSchedulerFields(dbObject);
-		Optional.ofNullable(dbObject.get("computational_resources")).map(cr -> (List<DBObject>) cr)
-				.ifPresent(computationalResources -> computationalResources.forEach(this::updateSchedulerFields));
-		userInstances.update(new BasicDBObject(ID, dbObject.get(ID)), dbObject);
-	}
-
-	private void updateSchedulerFields(DBObject dbObject) {
-		final Object schedulerData = dbObject.get("scheduler_data");
-		if (schedulerData != null) {
-			final Object daysRepeat = ((DBObject) schedulerData).removeField("days_repeat");
-			((DBObject) schedulerData).put("start_days_repeat", daysRepeat);
-			((DBObject) schedulerData).put("stop_days_repeat", daysRepeat);
-		}
-	}
-}
diff --git a/services/dlab-utils/pom.xml b/services/dlab-utils/pom.xml
deleted file mode 100644
index d79a326..0000000
--- a/services/dlab-utils/pom.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ 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.
-  -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <artifactId>dlab</artifactId>
-        <groupId>com.epam.dlab</groupId>
-        <version>1.0</version>
-        <relativePath>../../pom.xml</relativePath>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>dlab-utils</artifactId>
-
-    <dependencies>
-        <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>common</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>io.dropwizard</groupId>
-            <artifactId>dropwizard-jackson</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-core</artifactId>
-            <version>${org.mockito.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-</project>
\ No newline at end of file
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/FileUtils.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/FileUtils.java
deleted file mode 100644
index 251902c..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/FileUtils.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.util;
-
-import com.epam.dlab.exceptions.DlabException;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-
-@Slf4j
-public class FileUtils {
-
-	private FileUtils() {
-	}
-
-	public static void saveToFile(String filename, String directory, String content) throws IOException {
-		java.nio.file.Path filePath = Paths.get(directory, filename).toAbsolutePath();
-		log.debug("Saving content to {}", filePath.toString());
-		try {
-			com.google.common.io.Files.createParentDirs(new File(filePath.toString()));
-		} catch (IOException e) {
-			throw new DlabException("Can't create folder " + filePath + ": " + e.getLocalizedMessage(), e);
-		}
-		Files.write(filePath, content.getBytes());
-	}
-
-	public static void deleteFile(String filename, String directory) throws IOException {
-		java.nio.file.Path filePath = Paths.get(directory, filename).toAbsolutePath();
-		log.debug("Deleting file from {}", filePath.toString());
-		Files.deleteIfExists(filePath);
-	}
-
-	public static void deleteFile(String absolutePath) {
-		log.debug("Deleting file from {}", absolutePath);
-		try {
-			Files.deleteIfExists(Paths.get(absolutePath));
-		} catch (IOException e) {
-			log.error("Problems occured with deleting file {} due to: {}", absolutePath, e.getLocalizedMessage(), e);
-		}
-	}
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/SecurityUtils.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/SecurityUtils.java
deleted file mode 100644
index 03c2760..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/SecurityUtils.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.util;
-
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-public class SecurityUtils {
-
-	private static final String PASS_REGEX = "\"password\":\".+?\"";
-	private static final String PASS_REPLACEMENT = "\"password\":\"\\*\\*\\*\"";
-
-	private SecurityUtils() {
-	}
-
-	public static String hideCreds(String... strings) {
-		return Stream.of(strings)
-				.map(str -> str.replaceAll(PASS_REGEX, PASS_REPLACEMENT))
-				.collect(Collectors.joining(" "));
-	}
-
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/ServiceUtils.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/ServiceUtils.java
deleted file mode 100644
index d3a44b2..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/ServiceUtils.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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.util;
-
-import com.epam.dlab.exceptions.DlabException;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-import java.net.JarURLConnection;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.jar.Attributes;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-
-@Slf4j
-public class ServiceUtils {
-
-	private static String includePath = null;
-
-	static {
-		includePath = System.getenv("DLAB_CONF_DIR");
-		if ( includePath == null || includePath.isEmpty() ) {
-			includePath = getUserDir();
-		}
-	}
-
-	/* Return working directory.
-	 */
-	public static String getUserDir() {
-		return System.getProperty("user.dir");
-	}
-
-	/** Return path to DLab configuration directory.
-	 * @return
-	 */
-	public static String getConfPath() {
-		return includePath;
-	}
-
-
-	/** Return manifest for given class or empty manifest if {@link JarFile#MANIFEST_NAME} not found.
-	 * @param clazz class.
-	 * @throws IOException
-	 */
-	private static Manifest getManifestForClass(Class<?> clazz) throws IOException {
-		URL url = clazz.getClassLoader().getResource(JarFile.MANIFEST_NAME);
-		return (url == null ? new Manifest() : new Manifest(url.openStream()));
-	}
-
-	/** Return manifest from JAR file.
-	 * @param classPath path to class in JAR file.
-	 * @throws IOException
-	 */
-	private static Manifest getManifestFromJar(String classPath) throws IOException {
-		URL url = new URL(classPath);
-		JarURLConnection jarConnection = (JarURLConnection) url.openConnection();
-		return jarConnection.getManifest();
-	}
-
-	/** Return manifest map for given class or empty map if manifest not found or cannot be read.
-	 * @param clazz class.
-	 */
-	public static Map<String, String> getManifest(Class<?> clazz) {
-		String className = "/" + clazz.getName().replace('.', '/') + ".class";
-		String classPath = clazz.getResource(className).toString();
-
-		Map<String, String> map = new HashMap<>();
-		try {
-			Manifest manifest = (classPath.startsWith("jar:file:") ? getManifestFromJar(classPath) : getManifestForClass(clazz));
-			Attributes attributes = manifest.getMainAttributes();
-			for (Object key : attributes.keySet()) {
-				map.put(key.toString(), (String) attributes.get(key));
-			}
-		} catch (IOException e) {
-			log.error("Cannot found or open manifest for class {}", className, e);
-			throw new DlabException("Cannot read manifest file", e);
-		}
-
-		return map;
-	}
-
-	/** Print to standard output the manifest info about application. If parameter <b>args</b> is not
-	 * <b>null</b> and one or more arguments have value -v or --version then print version and return <b>true<b/>
-	 * otherwise <b>false</b>.
-	 * @param mainClass the main class of application.
-	 * @param args the arguments of main class function or null.
-	 * @return if parameter <b>args</b> is not null and one or more arguments have value -v or --version
-	 * then return <b>true<b/> otherwise <b>false</b>.
-	 */
-	public static boolean printAppVersion(Class<?> mainClass, String ... args) {
-		boolean result = false;
-		if (args != null) {
-			for (String arg : args) {
-				if ("-v".equals(arg) ||
-						"--version".equals(arg)) {
-					result = true;
-				}
-			}
-			if (!result) {
-				return result;
-			}
-		}
-
-		Map<String, String> manifest = getManifest(mainClass);
-		if (manifest.isEmpty()) {
-			return result;
-		}
-
-		log.info("Title       {}", manifest.get("Implementation-Title"));
-		log.info("Version     {}", manifest.get("Implementation-Version"));
-		log.info("Created By  {}", manifest.get("Created-By"));
-		log.info("Vendor      {}", manifest.get("Implementation-Vendor"));
-		log.info("GIT-Branch  {}", manifest.get("GIT-Branch"));
-		log.info("GIT-Commit  {}", manifest.get("GIT-Commit"));
-		log.info("Build JDK   {}", manifest.get("Build-Jdk"));
-		log.info("Build OS    {}", manifest.get("Build-OS"));
-		log.info("Built Time  {}", manifest.get("Build-Time"));
-		log.info("Built By    {}", manifest.get("Built-By"));
-
-		return result;
-	}
-}
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
deleted file mode 100644
index 4d1092c..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/UsernameUtils.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.util;
-
-public class UsernameUtils {
-
-	private static final String UNDERLINE = "_";
-
-	private UsernameUtils() {
-	}
-
-	public static String removeDomain(String username) {
-		return username != null ? username.replaceAll("@.*", "") : null;
-	}
-
-	public static String replaceWhitespaces(String username) {
-		return username.replaceAll("\\s", UNDERLINE);
-	}
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoDateDeSerializer.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoDateDeSerializer.java
deleted file mode 100644
index 1a337ea..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoDateDeSerializer.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.util.mongo;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.ObjectCodec;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonNode;
-
-import java.io.IOException;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-/**
- * Deserializes {@link java.util.Date} from JSON
- */
-public class IsoDateDeSerializer extends JsonDeserializer<Date> {
-    static final String DATE_NODE = "$date";
-    static final String ISO_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
-
-    @Override
-    public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
-        ObjectCodec oc = jsonParser.getCodec();
-        JsonNode node = oc.readTree(jsonParser);
-
-        Date date;
-        if (node.get(DATE_NODE) != null) {
-            String dateValue = node.get(DATE_NODE).asText();
-            DateFormat df = new SimpleDateFormat(ISO_DATE_FORMAT);
-            try {
-                date = df.parse(dateValue);
-            } catch (ParseException e) {
-                date = new Date(Long.valueOf(dateValue));
-            }
-        } else {
-            date = new Date(node.asLong());
-        }
-        return date;
-    }
-
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoDateSerializer.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoDateSerializer.java
deleted file mode 100644
index 4ffee23..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoDateSerializer.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.util.mongo;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-
-import java.io.IOException;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.TimeZone;
-
-/**
- * Serializes the {@link java.util.Date} to JSON
- */
-public class IsoDateSerializer extends JsonSerializer<Date> {
-
-    @Override
-    public void serialize(Date date, JsonGenerator gen, SerializerProvider serializers) throws IOException {
-        DateFormat df = new SimpleDateFormat(IsoDateDeSerializer.ISO_DATE_FORMAT);
-        df.setTimeZone(TimeZone.getTimeZone("GMT"));
-        String dateValue = df.format(date);
-
-        gen.writeStartObject();
-        gen.writeFieldName(IsoDateDeSerializer.DATE_NODE);
-        gen.writeString(dateValue);
-        gen.writeEndObject();
-    }
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoLocalDateDeSerializer.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoLocalDateDeSerializer.java
deleted file mode 100644
index f6803cf..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoLocalDateDeSerializer.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.util.mongo;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.ObjectCodec;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonNode;
-
-import java.io.IOException;
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.ZoneOffset;
-
-import static com.epam.dlab.util.mongo.IsoDateDeSerializer.DATE_NODE;
-
-public class IsoLocalDateDeSerializer extends JsonDeserializer<LocalDate> {
-	@Override
-	public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
-		ObjectCodec oc = p.getCodec();
-		JsonNode node = oc.readTree(p);
-		if (node.get(DATE_NODE) != null) {
-			String dateValue = node.get(DATE_NODE).asText();
-			return Instant.ofEpochMilli(Long.valueOf(dateValue)).atZone(ZoneOffset.systemDefault()).toLocalDate();
-		} else {
-			return Instant.ofEpochMilli(node.asLong()).atZone(ZoneOffset.systemDefault()).toLocalDate();
-		}
-	}
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoLocalDateSerializer.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoLocalDateSerializer.java
deleted file mode 100644
index c5e428e..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoLocalDateSerializer.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.util.mongo;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-
-import java.io.IOException;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-
-public class IsoLocalDateSerializer extends JsonSerializer<LocalDate> {
-	@Override
-	public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
-		gen.writeStartObject();
-		gen.writeFieldName(IsoDateDeSerializer.DATE_NODE);
-		gen.writeString(value.format(DateTimeFormatter.ISO_DATE));
-		gen.writeEndObject();
-	}
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoLocalDateTimeDeSerializer.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoLocalDateTimeDeSerializer.java
deleted file mode 100644
index 0e271ed..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoLocalDateTimeDeSerializer.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.util.mongo;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.ObjectCodec;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonNode;
-
-import java.io.IOException;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
-
-import static com.epam.dlab.util.mongo.IsoDateDeSerializer.DATE_NODE;
-
-public class IsoLocalDateTimeDeSerializer extends JsonDeserializer<LocalDateTime> {
-
-	@Override
-	public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
-		ObjectCodec oc = p.getCodec();
-		JsonNode node = oc.readTree(p);
-		if (node.get(DATE_NODE) != null) {
-			String dateValue = node.get(DATE_NODE).asText();
-			return Instant.ofEpochMilli(Long.valueOf(dateValue)).atZone(ZoneOffset.systemDefault()).toLocalDateTime();
-		} else {
-			return Instant.ofEpochMilli(node.asLong()).atZone(ZoneOffset.systemDefault()).toLocalDateTime();
-		}
-	}
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoLocalDateTimeSerializer.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoLocalDateTimeSerializer.java
deleted file mode 100644
index 87e0608..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/IsoLocalDateTimeSerializer.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.util.mongo;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-
-import java.io.IOException;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-
-public class IsoLocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
-	@Override
-	public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
-		gen.writeStartObject();
-		gen.writeFieldName(IsoDateDeSerializer.DATE_NODE);
-		gen.writeString(value.format(DateTimeFormatter.ISO_DATE_TIME));
-		gen.writeEndObject();
-	}
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/LongDeSerializer.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/LongDeSerializer.java
deleted file mode 100644
index c7a5ee3..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/LongDeSerializer.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.util.mongo;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.ObjectCodec;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonNode;
-
-import java.io.IOException;
-
-public class LongDeSerializer extends JsonDeserializer<Long> {
-	private static final String NUMBER_NODE = "$numberLong";
-
-	@Override
-	public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
-		ObjectCodec oc = p.getCodec();
-		JsonNode node = oc.readTree(p);
-
-		final JsonNode numberNode = node.get(NUMBER_NODE);
-		if (numberNode != null) {
-			return numberNode.asLong();
-		} else {
-			return node.asLong();
-		}
-	}
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/MongoStringDeserializer.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/MongoStringDeserializer.java
deleted file mode 100644
index 4c1a37a..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/MongoStringDeserializer.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.util.mongo;
-
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.KeyDeserializer;
-
-import static com.epam.dlab.util.mongo.MongoStringSerializaer.DOT_UNICODE;
-
-public class MongoStringDeserializer extends KeyDeserializer {
-
-	@Override
-	public Object deserializeKey(String key, DeserializationContext ctxt) {
-		return key.contains(DOT_UNICODE) ? key.replace(DOT_UNICODE, ".") : key;
-	}
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/MongoStringSerializaer.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/MongoStringSerializaer.java
deleted file mode 100644
index 5b9fdca..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/MongoStringSerializaer.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.util.mongo;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-
-import java.io.IOException;
-
-public class MongoStringSerializaer extends JsonSerializer<String> {
-	public static final String DOT_UNICODE = "U+FF0E";
-
-	@Override
-	public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
-		if (value.contains(".")) {
-			gen.writeFieldName(value.replace(".", DOT_UNICODE));
-		} else {
-			gen.writeFieldName(value);
-		}
-	}
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/modules/IsoDateModule.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/modules/IsoDateModule.java
deleted file mode 100644
index 290f5ab..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/modules/IsoDateModule.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.util.mongo.modules;
-
-import com.epam.dlab.util.mongo.*;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-import com.fasterxml.jackson.datatype.jsr310.deser.JSR310StringParsableDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
-
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.ZoneOffset;
-import java.util.Date;
-
-/**
- * Serialization/Deserialization modul for {@link java.util.Date} that uses {@link IsoDateDeSerializer} and
- * {@link IsoDateSerializer}
- */
-public class IsoDateModule extends SimpleModule {
-	private static final long serialVersionUID = -2103066255354028256L;
-
-	public IsoDateModule() {
-		super();
-		addSerializer(Date.class, new IsoDateSerializer());
-		addDeserializer(Date.class, new IsoDateDeSerializer());
-
-		addSerializer(LocalDate.class, new IsoLocalDateSerializer());
-		addDeserializer(LocalDate.class, new IsoLocalDateDeSerializer());
-
-		addSerializer(LocalTime.class, new ToStringSerializer(LocalTime.class));
-		addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE);
-
-		addSerializer(LocalDateTime.class, new IsoLocalDateTimeSerializer());
-		addDeserializer(LocalDateTime.class, new IsoLocalDateTimeDeSerializer());
-
-		addSerializer(ZoneOffset.class, new ToStringSerializer(ZoneOffset.class));
-		addDeserializer(ZoneOffset.class, JSR310StringParsableDeserializer.ZONE_OFFSET);
-
-	}
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/modules/JavaPrimitiveModule.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/modules/JavaPrimitiveModule.java
deleted file mode 100644
index 83011ff..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/modules/JavaPrimitiveModule.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.util.mongo.modules;
-
-import com.epam.dlab.util.mongo.LongDeSerializer;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-
-public class JavaPrimitiveModule extends SimpleModule {
-
-	public JavaPrimitiveModule() {
-		addDeserializer(Long.class, new LongDeSerializer());
-	}
-
-}
diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/modules/MongoModule.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/modules/MongoModule.java
deleted file mode 100644
index 2218b6f..0000000
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/mongo/modules/MongoModule.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.util.mongo.modules;
-
-import com.epam.dlab.util.mongo.MongoStringDeserializer;
-import com.epam.dlab.util.mongo.MongoStringSerializaer;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-
-public class MongoModule extends SimpleModule {
-
-	public MongoModule() {
-		addKeySerializer(String.class, new MongoStringSerializaer());
-		addKeyDeserializer(String.class, new MongoStringDeserializer());
-	}
-}
diff --git a/services/dlab-utils/src/test/java/com/epam/dlab/util/SecurityUtilsTest.java b/services/dlab-utils/src/test/java/com/epam/dlab/util/SecurityUtilsTest.java
deleted file mode 100644
index b77429a..0000000
--- a/services/dlab-utils/src/test/java/com/epam/dlab/util/SecurityUtilsTest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.util;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SecurityUtilsTest {
-
-	@Test
-	public void hideCredsTest() {
-		String[] strings = {"bash", "-c", "\"edge_user_name\":\"edgeUserName\",\"conf_service_base_name\":\"SBN\", " +
-				"\"password\":\"12345\""};
-		String actual = SecurityUtils.hideCreds(strings);
-		String expected = "bash -c \"edge_user_name\":\"edgeUserName\",\"conf_service_base_name\":\"SBN\", " +
-				"\"password\":\"***\"";
-		Assert.assertEquals(expected, actual);
-	}
-}
diff --git a/services/dlab-utils/src/test/java/com/epam/dlab/util/mongo/IsoLocalDateTimeDeSerializerTest.java b/services/dlab-utils/src/test/java/com/epam/dlab/util/mongo/IsoLocalDateTimeDeSerializerTest.java
deleted file mode 100644
index 8d2d7af..0000000
--- a/services/dlab-utils/src/test/java/com/epam/dlab/util/mongo/IsoLocalDateTimeDeSerializerTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.util.mongo;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.ObjectCodec;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonNode;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.io.IOException;
-
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class IsoLocalDateTimeDeSerializerTest {
-
-	@Test
-	public void deserialize() throws IOException {
-		JsonParser jsonParser = mock(JsonParser.class);
-		DeserializationContext ctxt = mock(DeserializationContext.class);
-
-		ObjectCodec objectCodec = mock(ObjectCodec.class);
-		when(jsonParser.getCodec()).thenReturn(objectCodec);
-
-		JsonNode jsonNode = mock(JsonNode.class);
-		when(objectCodec.readTree(jsonParser)).thenReturn(jsonNode);
-
-		JsonNode jsonNode2 = mock(JsonNode.class);
-		when(jsonNode.get(anyString())).thenReturn(jsonNode2);
-		when(jsonNode2.asText()).thenReturn("1234567890");
-
-		new IsoLocalDateTimeDeSerializer().deserialize(jsonParser, ctxt);
-
-		verify(jsonParser).getCodec();
-		verify(objectCodec).readTree(jsonParser);
-		verify(jsonNode, times(2)).get("$date");
-		verify(jsonNode2).asText();
-		verify(jsonNode, never()).asLong();
-		verifyNoMoreInteractions(jsonParser, objectCodec, jsonNode, jsonNode2);
-	}
-
-	@Test
-	public void deserializeWhenMethodGetReturnsNull() throws IOException {
-		JsonParser jsonParser = mock(JsonParser.class);
-		DeserializationContext ctxt = mock(DeserializationContext.class);
-
-		ObjectCodec objectCodec = mock(ObjectCodec.class);
-		when(jsonParser.getCodec()).thenReturn(objectCodec);
-
-		JsonNode jsonNode = mock(JsonNode.class);
-		when(objectCodec.readTree(jsonParser)).thenReturn(jsonNode);
-
-		when(jsonNode.get(anyString())).thenReturn(null);
-
-		new IsoLocalDateTimeDeSerializer().deserialize(jsonParser, ctxt);
-
-		verify(jsonParser).getCodec();
-		verify(objectCodec).readTree(jsonParser);
-		verify(jsonNode).get("$date");
-		verify(jsonNode).asLong();
-		verifyNoMoreInteractions(jsonParser, objectCodec, jsonNode);
-	}
-}
\ No newline at end of file
diff --git a/services/dlab-utils/src/test/java/com/epam/dlab/util/mongo/IsoLocalDateTimeSerDeTest.java b/services/dlab-utils/src/test/java/com/epam/dlab/util/mongo/IsoLocalDateTimeSerDeTest.java
deleted file mode 100644
index 96a6e4c..0000000
--- a/services/dlab-utils/src/test/java/com/epam/dlab/util/mongo/IsoLocalDateTimeSerDeTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.util.mongo;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-
-import static org.junit.Assert.assertEquals;
-
-public class IsoLocalDateTimeSerDeTest {
-
-	private static ObjectMapper objectMapper;
-
-	@BeforeClass
-	public static void setup() {
-		objectMapper = new ObjectMapper();
-	}
-
-	@Test
-	public void shoudProperlySerializeLocalDateTimeToJson() throws JsonProcessingException {
-		String actual = objectMapper.writeValueAsString(new SampleClass());
-		assertEquals("{\"localDateTime\":{\"$date\":\"2018-04-10T15:30:45\"}}", actual);
-	}
-
-	@Test
-	public void shoudProperlyDeserializeLocalDateTimeFromJson() throws IOException {
-		LocalDateTime now = LocalDateTime.now();
-		long l = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
-		SampleClass actual = objectMapper
-				.readValue("{\"localDateTime\":{\"$date\":" + l + "}}", SampleClass.class);
-
-		assertEquals(now, actual.getLocalDateTime());
-	}
-
-	private static class SampleClass {
-
-		@JsonSerialize(using = IsoLocalDateTimeSerializer.class)
-		@JsonDeserialize(using = IsoLocalDateTimeDeSerializer.class)
-		private final LocalDateTime localDateTime = LocalDateTime.parse("2018-04-10T15:30:45");
-
-		LocalDateTime getLocalDateTime() {
-			return localDateTime;
-		}
-	}
-}
diff --git a/services/dlab-utils/src/test/java/com/epam/dlab/util/mongo/IsoLocalDateTimeSerializerTest.java b/services/dlab-utils/src/test/java/com/epam/dlab/util/mongo/IsoLocalDateTimeSerializerTest.java
deleted file mode 100644
index a588bb5..0000000
--- a/services/dlab-utils/src/test/java/com/epam/dlab/util/mongo/IsoLocalDateTimeSerializerTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.util.mongo;
-
-import com.fasterxml.jackson.databind.SerializerProvider;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.io.IOException;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class IsoLocalDateTimeSerializerTest {
-
-	@Test
-	public void serialize() throws IOException {
-		com.fasterxml.jackson.core.JsonGenerator jsonGenerator = mock(com.fasterxml.jackson.core.JsonGenerator.class);
-		SerializerProvider serializerProvider = mock(SerializerProvider.class);
-
-		LocalDateTime localDateTime = LocalDateTime.now();
-
-		new IsoLocalDateTimeSerializer().serialize(localDateTime, jsonGenerator, serializerProvider);
-
-		verify(jsonGenerator).writeStartObject();
-		verify(jsonGenerator).writeFieldName("$date");
-		verify(jsonGenerator).writeString(localDateTime.format(DateTimeFormatter.ISO_DATE_TIME));
-		verify(jsonGenerator).writeEndObject();
-		verifyNoMoreInteractions(jsonGenerator);
-		verifyZeroInteractions(serializerProvider);
-	}
-
-
-}
\ No newline at end of file
diff --git a/services/dlab-webapp-common/pom.xml b/services/dlab-webapp-common/pom.xml
deleted file mode 100644
index 2e7ad5c..0000000
--- a/services/dlab-webapp-common/pom.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ 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.
-  -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <artifactId>dlab</artifactId>
-        <groupId>com.epam.dlab</groupId>
-        <version>1.0</version>
-        <relativePath>../../pom.xml</relativePath>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>dlab-webapp-common</artifactId>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.mongodb</groupId>
-            <artifactId>mongo-java-driver</artifactId>
-            <version>${org.mongodb.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>com.google.inject</groupId>
-            <artifactId>guice</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>io.dropwizard</groupId>
-            <artifactId>dropwizard-jackson</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>io.dropwizard</groupId>
-            <artifactId>dropwizard-auth</artifactId>
-            <version>${io.dropwizard.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>io.dropwizard</groupId>
-            <artifactId>dropwizard-client</artifactId>
-            <version>${io.dropwizard.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>io.dropwizard</groupId>
-            <artifactId>dropwizard-forms</artifactId>
-            <version>${io.dropwizard.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>common</artifactId>
-        </dependency>
-    </dependencies>
-</project>
\ No newline at end of file
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/ModuleBase.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/ModuleBase.java
deleted file mode 100644
index ba2adca..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/ModuleBase.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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;
-
-import com.google.inject.AbstractModule;
-import io.dropwizard.setup.Environment;
-
-/**
- * The base class for an application configuration of service.
- */
-public abstract class ModuleBase<T extends ServiceConfiguration> extends AbstractModule {
-	/** Application configuration of service. */
-	protected T configuration;
-	/** Environment of service. */
-	protected Environment environment;
-
-	/** Instantiates an application configuration of service.
-	 * @param configuration application configuration of service.
-	 * @param environment environment of service.
-	 */
-	public ModuleBase(T configuration, Environment environment) {
-        this.configuration = configuration;
-        this.environment = environment;
-    }
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/ServiceConfiguration.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/ServiceConfiguration.java
deleted file mode 100644
index 1ae0afb..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/ServiceConfiguration.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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;
-
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.mongo.MongoServiceFactory;
-import com.epam.dlab.rest.client.RESTServiceFactory;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.dropwizard.Configuration;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-
-public class ServiceConfiguration extends Configuration {
-
-    @JsonProperty
-    private long inactiveUserTimeoutMillSec = 2 * 60L * 60L * 1000L;
-
-    @NotNull
-    @JsonProperty
-    private CloudProvider cloudProvider;
-
-    @Valid
-    @JsonProperty
-    private boolean devMode = false;
-
-    @Valid
-    @NotNull
-    @JsonProperty(ServiceConsts.MONGO_NAME)
-    private MongoServiceFactory mongoFactory = new MongoServiceFactory();
-
-    @Valid
-    @NotNull
-    @JsonProperty(ServiceConsts.PROVISIONING_SERVICE_NAME)
-    private RESTServiceFactory provisioningFactory = new RESTServiceFactory();
-
-    @Valid
-    @NotNull
-    @JsonProperty(ServiceConsts.BUCKET_SERVICE_NAME)
-    private RESTServiceFactory bucketFactory = new RESTServiceFactory();
-
-    @Valid
-    @NotNull
-    @JsonProperty(ServiceConsts.BILLING_SERVICE_NAME)
-    private RESTServiceFactory billingFactory = new RESTServiceFactory();
-
-    @Valid
-    @NotNull
-    @JsonProperty(ServiceConsts.SECURITY_SERVICE_NAME)
-    private RESTServiceFactory securityFactory;
-
-    @Valid
-    @NotNull
-    @JsonProperty(ServiceConsts.SELF_SERVICE_NAME)
-    private RESTServiceFactory selfFactory = new RESTServiceFactory();
-
-    public CloudProvider getCloudProvider() {
-        return cloudProvider;
-    }
-
-    public long getInactiveUserTimeoutMillSec() {
-        return inactiveUserTimeoutMillSec;
-    }
-
-    /**
-     * Returns <b>true</b> if service is a mock.
-     */
-    public boolean isDevMode() {
-        return devMode;
-    }
-
-    public MongoServiceFactory getMongoFactory() {
-        return mongoFactory;
-    }
-
-    public RESTServiceFactory getProvisioningFactory() {
-        return provisioningFactory;
-    }
-
-    public RESTServiceFactory getBucketFactory() {
-        return bucketFactory;
-    }
-
-    public RESTServiceFactory getBillingFactory() {
-        return billingFactory;
-    }
-
-    public RESTServiceFactory getSecurityFactory() {
-        return securityFactory;
-    }
-
-    public RESTServiceFactory getSelfFactory() {
-        return selfFactory;
-    }
-
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/SecurityUnauthorizedHandler.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/SecurityUnauthorizedHandler.java
deleted file mode 100644
index 91df79f..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/SecurityUnauthorizedHandler.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.auth;
-
-import io.dropwizard.auth.UnauthorizedHandler;
-
-import javax.ws.rs.core.Response;
-
-public class SecurityUnauthorizedHandler implements UnauthorizedHandler {
-    @Override
-    public Response buildResponse(String prefix, String realm) {
-        return Response.status(Response.Status.UNAUTHORIZED).build();
-    }
-
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/UserInfo.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/UserInfo.java
deleted file mode 100644
index c4b0f53..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/UserInfo.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * 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.auth;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonSetter;
-
-import java.security.Principal;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class UserInfo implements Principal {
-
-    private final String username;
-    private final String accessToken;
-    private String refreshToken;
-    private final Set<String> roles = new HashSet<>();
-    private final Map<String,String> keys = new HashMap<>();
-
-    @JsonProperty
-    private String firstName;
-    @JsonProperty
-    private String lastName;
-    @JsonProperty
-    private String remoteIp;
-    @JsonProperty
-    private boolean awsUser = false;
-
-    @JsonCreator
-    public UserInfo(@JsonProperty("username") String username,
-    				@JsonProperty("access_token") String accessToken) {
-        this.username = (username == null ? null : username.toLowerCase());
-        this.accessToken = accessToken;
-    }
-
-    @Override
-    @JsonProperty("username")
-    public String getName() {
-        return username;
-    }
-
-    public String getSimpleName() {
-        return (username == null ? null : username.replaceAll("@.*", ""));
-    }
-
-    @JsonProperty("access_token")
-    public String getAccessToken() {
-        return accessToken;
-    }
-
-    @JsonProperty("refresh_token")
-    public String getRefreshToken() {
-        return refreshToken;
-    }
-
-    public void setRefreshToken(String refreshToken) {
-        this.refreshToken = refreshToken;
-    }
-
-    @JsonProperty("roles")
-    public Set<String> getRoles() {
-        return roles;
-    }
-
-    //@JsonSetter("roles")
-    public void addRoles(Collection<String> r) {
-        roles.addAll(r);
-    }
-
-    @JsonSetter("roles")
-    public void addRoles(String[] r) {
-        roles.addAll(Arrays.asList(r));
-    }
-
-    public void addRole(String role) {
-        roles.add(role);
-    }
-
-
-    public String getFirstName() {
-        return firstName;
-    }
-
-    public void setFirstName(String firstName) {
-        this.firstName = firstName;
-    }
-
-    public String getLastName() {
-        return lastName;
-    }
-
-    public void setLastName(String lastName) {
-        this.lastName = lastName;
-    }
-
-    public String getRemoteIp() {
-		return remoteIp;
-	}
-
-	public void setRemoteIp(String remoteIp) {
-		this.remoteIp = remoteIp;
-	}
-
-	public UserInfo withToken(String token) {
-        UserInfo newInfo  = new UserInfo(username, token);
-        roles.forEach(newInfo::addRole);
-        newInfo.firstName = this.firstName;
-        newInfo.lastName  = this.lastName;
-        newInfo.remoteIp  = this.remoteIp;
-        newInfo.awsUser   = this.awsUser;
-        newInfo.setKeys(this.getKeys());
-        return newInfo;
-    }
-
-    public boolean isAwsUser() {
-        return awsUser;
-    }
-
-    public void setAwsUser(boolean awsUser) {
-        this.awsUser = awsUser;
-    }
-
-    public Map<String, String> getKeys() {
-        return keys;
-    }
-
-    public void addKey(String id, String status) {
-        keys.put(id,status);
-    }
-
-    @JsonSetter("keys")
-    public void setKeys(Map<String,String> awsKeys) {
-        awsKeys.forEach(keys::put);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-	    if (this == o) {
-		    return true;
-	    }
-	    if (o == null || getClass() != o.getClass()) {
-		    return false;
-	    }
-
-	    UserInfo userInfo = (UserInfo) o;
-
-	    if (awsUser != userInfo.awsUser) {
-		    return false;
-	    }
-	    if (username != null ? !username.equals(userInfo.username) : userInfo.username != null) {
-		    return false;
-	    }
-	    if (accessToken != null ? !accessToken.equals(userInfo.accessToken) : userInfo.accessToken != null)
-		    return false;
-	    if (!roles.equals(userInfo.roles)) {
-		    return false;
-	    }
-	    if (!keys.equals(userInfo.keys)) {
-		    return false;
-	    }
-	    if (firstName != null ? !firstName.equals(userInfo.firstName) : userInfo.firstName != null) {
-		    return false;
-	    }
-	    if (lastName != null ? !lastName.equals(userInfo.lastName) : userInfo.lastName != null) {
-		    return false;
-	    }
-	    return remoteIp != null ? remoteIp.equals(userInfo.remoteIp) : userInfo.remoteIp == null;
-    }
-
-
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(username,
-                accessToken,
-                roles,
-                keys,
-                firstName,
-                lastName,
-                remoteIp,
-                awsUser);
-    }
-
-    @Override
-    public String toString() {
-        return "UserInfo{" +
-                "username='" + username + '\'' +
-                ", accessToken='" + accessToken + '\'' +
-                ", refreshToken='" + refreshToken + '\'' +
-                ", roles=" + roles +
-                ", keys=" + keys.keySet() +
-                ", firstName='" + firstName + '\'' +
-                ", lastName='" + lastName + '\'' +
-                ", remoteIp='" + remoteIp + '\'' +
-                ", awsUser=" + awsUser +
-                '}';
-    }
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/contract/SecurityAPI.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/contract/SecurityAPI.java
deleted file mode 100644
index 9ce14c3..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/contract/SecurityAPI.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.auth.contract;
-
-public interface SecurityAPI {
-	String LOGIN = "login";
-	String LOGIN_OAUTH = LOGIN + '/' + "oauth";
-	String LOGIN_OAUTH_AZURE = "user/azure/oauth";
-	String GET_USER_INFO = "getuserinfo";
-	String LOGOUT = "logout";
-	String INIT_LOGIN_OAUTH_AZURE = "/user/azure/init";
-	String INIT_LOGIN_OAUTH_GCP = "/user/gcp/init";
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/dto/UserCredentialDTO.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/dto/UserCredentialDTO.java
deleted file mode 100644
index 80f130f..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/dto/UserCredentialDTO.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.auth.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-import org.hibernate.validator.constraints.NotBlank;
-
-public class UserCredentialDTO {
-    @NotBlank
-    @JsonProperty
-    private String username;
-
-    @NotBlank
-    @JsonProperty
-    private String password;
-
-    @JsonProperty("access_token")
-    private String accessToken;
-
-    public String getUsername() {
-        return username;
-    }
-
-    public void setUsername(String username) {
-    	this.username = (username == null ? null : username.toLowerCase());
-    }
-
-    public String getPassword() {
-        return password;
-    }
-
-    public void setPassword(String password) {
-        this.password = password;
-    }
-
-    public String getAccessToken() {
-        return accessToken;
-    }
-
-    public void setAccessToken(String accessToken) {
-        this.accessToken = accessToken;
-    }
-
-    public ToStringHelper toStringHelper(Object self) {
-    	return MoreObjects.toStringHelper(self)
-    	        .add("username", username)
-    	        .add("password", password == null ? null : "***")
-    	        .add("accessToken", accessToken == null ? null : "***");
-    }
-    
-    @Override
-    public String toString() {
-    	return toStringHelper(this).toString();
-    }
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/oauth2/Oauth2AuthenticationService.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/oauth2/Oauth2AuthenticationService.java
deleted file mode 100644
index e998772..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/oauth2/Oauth2AuthenticationService.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.auth.oauth2;
-
-public interface Oauth2AuthenticationService {
-
-	/**
-	 * @return redirected ulr
-	 */
-	String getRedirectedUrl();
-
-	/**
-	 * Authorize user using oauth authorization code
-	 *
-	 * @param code  authorization code
-	 * @param state state
-	 * @return token
-	 */
-	String authorize(String code, String state);
-
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/rest/AbstractAuthenticationService.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/rest/AbstractAuthenticationService.java
deleted file mode 100644
index 1ef65f7..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/rest/AbstractAuthenticationService.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.auth.rest;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.auth.dto.UserCredentialDTO;
-import io.dropwizard.Configuration;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.core.Response;
-import java.util.UUID;
-
-public abstract class AbstractAuthenticationService<C extends Configuration> extends ConfigurableResource<C> {
-
-	public AbstractAuthenticationService(C config) {
-		super(config);
-	}
-
-	public static String getRandomToken() {
-		return UUID.randomUUID().toString();
-	}
-
-	public abstract Response login(UserCredentialDTO credential, HttpServletRequest request);
-
-	public abstract UserInfo getUserInfo(String accessToken, HttpServletRequest request);
-
-	public abstract Response logout(String accessToken);
-
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/rest/ConfigurableResource.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/rest/ConfigurableResource.java
deleted file mode 100644
index e7af37d..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/rest/ConfigurableResource.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.auth.rest;
-
-import io.dropwizard.Configuration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public abstract class ConfigurableResource<C extends Configuration> {
-
-	protected final Logger log;
-	protected final C config;
-	
-	public ConfigurableResource(C config) {
-		this.log    = LoggerFactory.getLogger(getClass());
-		this.config = config;
-	}
-	
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/rest/UserSessionDurationAuthorizer.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/rest/UserSessionDurationAuthorizer.java
deleted file mode 100644
index 2f346e8..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/rest/UserSessionDurationAuthorizer.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.auth.rest;
-
-import com.epam.dlab.auth.UserInfo;
-import io.dropwizard.auth.Authorizer;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.Date;
-
-@Slf4j
-public final class UserSessionDurationAuthorizer implements Authorizer<UserInfo> {
-    public static final String SHORT_USER_SESSION_DURATION = "SHORT_USER_SESSION";
-    private final long maxSessionDurabilityMilliseconds;
-    private UserSessionDurationCallback callback;
-
-    public UserSessionDurationAuthorizer(UserSessionDurationCallback callback, long maxSessionDurabilityMilliseconds) {
-        this.callback = callback;
-        this.maxSessionDurabilityMilliseconds = maxSessionDurabilityMilliseconds;
-    }
-
-    @Override
-    public boolean authorize(UserInfo principal, String role) {
-        if (SHORT_USER_SESSION_DURATION.equalsIgnoreCase(role)) {
-            try {
-                String refreshToken = principal.getKeys().get("refresh_token");
-                String createdDateOfRefreshToken = principal.getKeys().get("created_date_of_refresh_token");
-
-                if (StringUtils.isEmpty(refreshToken)) {
-                    log.info("Refresh token is empty for user {}", principal.getName());
-                    return false;
-                }
-
-                if (StringUtils.isEmpty(createdDateOfRefreshToken)) {
-                    log.info("Created date for refresh token is empty for user {}", principal.getName());
-                    return false;
-                }
-
-                log.debug("refresh token requested {} and current date is {}",
-                        new Date(Long.valueOf(createdDateOfRefreshToken)), new Date());
-
-                long passedTime = System.currentTimeMillis() - Long.valueOf(createdDateOfRefreshToken);
-
-                log.info("Passed time of session for user {} is {} milliseconds", principal.getName(), passedTime);
-                if (passedTime > maxSessionDurabilityMilliseconds) {
-
-                    silentCallbackExecution(principal);
-
-                    log.info("Re-login required for user {}", principal.getName());
-                    return false;
-                }
-
-                return true;
-            } catch (RuntimeException e) {
-                log.error("Cannot verify durability of session for user {}", principal.getName(), e);
-                return false;
-            }
-
-        }
-
-        return true;
-    }
-
-    private void silentCallbackExecution(UserInfo principal) {
-        log.info("Log out expired user {}", principal.getName());
-        try {
-            callback.onSessionExpired(principal);
-        } catch (RuntimeException e) {
-            log.warn("Error during logout user {}", principal.getName(), e);
-        }
-    }
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/rest/UserSessionDurationCallback.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/rest/UserSessionDurationCallback.java
deleted file mode 100644
index 9f1cb28..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/rest/UserSessionDurationCallback.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.auth.rest;
-
-import com.epam.dlab.auth.UserInfo;
-
-@FunctionalInterface
-public interface UserSessionDurationCallback {
-    void onSessionExpired(UserInfo userInfo);
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/cloud/CloudModule.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/cloud/CloudModule.java
deleted file mode 100644
index 806e7e0..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/cloud/CloudModule.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.cloud;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.Injector;
-import io.dropwizard.setup.Environment;
-
-public abstract class CloudModule extends AbstractModule {
-
-    @Override
-    protected void configure() {
-    }
-
-    public abstract void init(Environment environment, Injector injector);
-
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/cloud/CloudProvider.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/cloud/CloudProvider.java
deleted file mode 100644
index f148e29..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/cloud/CloudProvider.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.cloud;
-
-public enum CloudProvider {
-    AWS, AZURE, GCP;
-
-    public String getName() {
-        return this.toString().toLowerCase();
-    }
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
deleted file mode 100644
index b04db9f..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/constants/ServiceConsts.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.constants;
-
-public final class ServiceConsts {
-	public static final String MONGO_NAME = "mongo";
-	public static final String PROVISIONING_SERVICE_NAME = "provisioningService";
-	public static final String BILLING_SERVICE_NAME = "billingService";
-	public static final String BUCKET_SERVICE_NAME = "bucketService";
-	public static final String MAVEN_SEARCH_API = "mavenSearchService";
-	public static final String SECURITY_SERVICE_NAME = "securityService";
-	public static final String SELF_SERVICE_NAME = "selfService";
-	public static final String PROVISIONING_USER_AGENT = "provisioning-service";
-
-	private ServiceConsts() {
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/mongo/MongoService.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/mongo/MongoService.java
deleted file mode 100644
index e232551..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/mongo/MongoService.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.mongo;
-
-import com.mongodb.MongoClient;
-import com.mongodb.WriteConcern;
-import com.mongodb.client.MongoCollection;
-import com.mongodb.client.MongoDatabase;
-import org.bson.Document;
-
-public class MongoService {
-    private MongoClient client;
-    private String databaseName;
-    private MongoDatabase database;
-
-    private static final Document PING = new Document("ping", "1");
-
-    public MongoService(MongoClient client,
-                        String databaseName,
-                        WriteConcern writeConcern) {
-        this(client, databaseName);
-        database = database.withWriteConcern(writeConcern);
-    }
-
-    public MongoService(MongoClient client, String databaseName) {
-        this.client = client;
-        this.databaseName = databaseName;
-        this.database = client.getDatabase(databaseName);
-    }
-
-    public boolean collectionExists(String name) {
-        for (String c : database.listCollectionNames()) {
-        	if (c.equals(name)) {
-        		return true;
-        	}
-        }
-        return false;
-    }
-
-    public MongoCollection<Document> getCollection(String name) {
-        return database.getCollection(name, Document.class);
-    }
-
-    public <T> MongoCollection<T> getCollection(String name, Class<T> c) {
-        return database.getCollection(name, c);
-    }
-
-    public void createCollection(String name) {
-        database.createCollection(name);
-    }
-    
-    public String getDatabaseName() {
-    	return databaseName;
-    }
-
-    public MongoClient getClient() {
-    	return client;
-    }
-    
-    public Document ping() {
-        return database.runCommand(PING);
-    }
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/mongo/MongoServiceFactory.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/mongo/MongoServiceFactory.java
deleted file mode 100644
index b0194df..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/mongo/MongoServiceFactory.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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.mongo;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.mongodb.MongoClient;
-import com.mongodb.MongoCredential;
-import com.mongodb.ServerAddress;
-import io.dropwizard.lifecycle.Managed;
-import io.dropwizard.setup.Environment;
-import org.hibernate.validator.constraints.NotEmpty;
-
-import javax.validation.constraints.Max;
-import javax.validation.constraints.Min;
-import java.util.Collections;
-
-// TODO: Separate configuration and factory responsibilities
-public class MongoServiceFactory {
-    @NotEmpty
-    @JsonProperty
-    private String host;
-
-    @Min(1)
-    @Max(65535)
-    @JsonProperty
-    private int port;
-
-    @NotEmpty
-    @JsonProperty
-    private String username;
-
-    @NotEmpty
-    @JsonProperty
-    private String password;
-
-    @NotEmpty
-    @JsonProperty
-    private String database;
-
-    public MongoService build(Environment environment) {
-        MongoClient client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(
-                MongoCredential.createCredential(username, database, password.toCharArray())
-        ));
-        environment.lifecycle().manage(new Managed() {
-            @Override
-            public void start() {
-            }
-
-            @Override
-            public void stop() {
-                client.close();
-            }
-        });
-        return new MongoService(client, database);
-    }
-
-    public String getHost() {
-        return host;
-    }
-
-    public int getPort() {
-        return port;
-    }
-
-    public String getUsername() {
-        return username;
-    }
-
-    public String getPassword() {
-        return password;
-    }
-
-    public String getDatabase() {
-        return database;
-    }
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTService.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTService.java
deleted file mode 100644
index 924862c..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTService.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * 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.rest.client;
-
-import lombok.extern.slf4j.Slf4j;
-import org.glassfish.jersey.media.multipart.Boundary;
-import org.glassfish.jersey.media.multipart.FormDataMultiPart;
-
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.Invocation;
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import java.net.URI;
-import java.util.Collections;
-import java.util.Map;
-
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA_TYPE;
-
-@Slf4j
-public class RESTService {
-	private Client client;
-	private String url;
-	private String userAgent;
-
-	public RESTService() {
-	}
-
-	RESTService(Client client, String url, String userAgent) {
-		this.client = client;
-		this.url = url;
-		this.userAgent = userAgent;
-	}
-
-	RESTService(Client client, String userAgent) {
-		this.client = client;
-		this.userAgent = userAgent;
-	}
-
-	public <T> T get(String path, Class<T> clazz) {
-		return get(path, null, clazz);
-	}
-
-	public <T> T get(URI path, Class<T> clazz) {
-		log.debug("REST get {}", path);
-		return client.target(URI.create(url + path.toString()))
-				.request()
-				.get(clazz);
-	}
-
-	public <T> T getWithMediaTypes(String path, String accessToken, Class<T> clazz, String requestMediaType, String acceptMediaType) {
-		return get(path, accessToken, clazz, requestMediaType, acceptMediaType);
-	}
-
-	public <T> T get(String path, String accessToken, Class<T> clazz) {
-		return get(path, accessToken, clazz, APPLICATION_JSON, APPLICATION_JSON);
-	}
-
-	private <T> T get(String path, String accessToken, Class<T> clazz, String requestMediaType, String acceptMediaType) {
-		Invocation.Builder builder = getBuilder(path, accessToken, Collections.emptyMap(), requestMediaType, acceptMediaType);
-		log.debug("REST get secured {} {}", path, accessToken);
-		return builder.get(clazz);
-	}
-
-	public <T> T get(String path, GenericType<T> genericType) {
-		return get(path, null, genericType);
-	}
-
-	public <T> T get(String path, String accessToken, GenericType<T> genericType) {
-		return get(path, accessToken, genericType, Collections.emptyMap());
-	}
-
-	public <T> T get(String path, String accessToken, GenericType<T> genericType, Map<String, Object> queryParams) {
-		Invocation.Builder builder = getBuilder(path, accessToken, queryParams, APPLICATION_JSON, APPLICATION_JSON);
-		log.debug("REST get secured {} {}", path, accessToken);
-		return builder.get(genericType);
-	}
-
-	public <T> T post(String path, Object parameter, Class<T> clazz) {
-		return post(path, null, parameter, clazz);
-	}
-
-	public <T> T post(String path, String accessToken, Object parameter, Class<T> clazz) {
-		return post(path, accessToken, parameter, clazz, Collections.emptyMap(), APPLICATION_JSON, APPLICATION_JSON);
-	}
-
-	public <T> T delete(String path, String accessToken, Class<T> clazz, String requestMediaType, String acceptMediaType) {
-		return delete(path, accessToken, clazz, Collections.emptyMap(), requestMediaType, acceptMediaType);
-	}
-
-	private <T> T delete(String path, String accessToken, Class<T> clazz, Map<String, Object> queryParams,
-						 String requestMediaType, String acceptMediaType) {
-		Invocation.Builder builder = getBuilder(path, accessToken, queryParams, requestMediaType, acceptMediaType);
-		log.debug("REST delete secured {} {}", path, accessToken);
-		return builder.delete(clazz);
-	}
-
-	private <T> T post(String path, String accessToken, Object parameter, Class<T> clazz, Map<String, Object> queryParams,
-					   String requestMediaType, String acceptMediaType) {
-		Invocation.Builder builder = getBuilder(path, accessToken, queryParams, requestMediaType, acceptMediaType);
-		log.debug("REST post secured {} {}", path, accessToken);
-		return builder.post(Entity.json(parameter), clazz);
-	}
-
-
-	private Invocation.Builder getBuilder(String path, String token, Map<String, Object> queryParams,
-										  String requestMediaType, String acceptMediaType) {
-		WebTarget webTarget = getWebTarget(path);
-		for (Map.Entry<String, Object> entry : queryParams.entrySet()) {
-			webTarget = webTarget.queryParam(entry.getKey(), entry.getValue());
-		}
-
-		Invocation.Builder builder = webTarget
-				.request(requestMediaType)
-				.accept(acceptMediaType);
-
-		if (token != null) {
-			builder.header(HttpHeaders.AUTHORIZATION, "Bearer " + token);
-		}
-		if (userAgent != null) {
-			builder.header(HttpHeaders.USER_AGENT, userAgent);
-		}
-
-		return builder;
-	}
-
-	public <T> T postForm(String path, String token, FormDataMultiPart form, Class<T> clazz) {
-		WebTarget webTarget = getWebTarget(path);
-		Invocation.Builder builder = webTarget.request();
-		if (token != null) {
-			builder.header(HttpHeaders.AUTHORIZATION, "Bearer " + token);
-		}
-		if (userAgent != null) {
-			builder.header(HttpHeaders.USER_AGENT, userAgent);
-		}
-
-		MediaType mediaType = Boundary.addBoundary(MULTIPART_FORM_DATA_TYPE);
-		return builder.post(Entity.entity(form, mediaType), clazz);
-	}
-
-
-	private WebTarget getWebTarget(String path) {
-		return url != null ? client.target(url).path(path) : client.target(path);
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTServiceFactory.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTServiceFactory.java
deleted file mode 100644
index aeb0ad1..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/client/RESTServiceFactory.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.rest.client;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.dropwizard.client.JerseyClientBuilder;
-import io.dropwizard.client.JerseyClientConfiguration;
-import io.dropwizard.setup.Environment;
-import org.apache.commons.lang3.StringUtils;
-import org.glassfish.jersey.media.multipart.MultiPartFeature;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-import javax.ws.rs.client.Client;
-
-public class RESTServiceFactory {
-	@JsonProperty
-	private String protocol;
-
-	@JsonProperty
-	private String host;
-
-	@JsonProperty
-	private int port;
-
-	@Valid
-	@NotNull
-	@JsonProperty("jerseyClient")
-	private JerseyClientConfiguration jerseyClientConfiguration;
-
-	public RESTService build(Environment environment, String name) {
-		return build(environment, name, null);
-	}
-
-	public RESTService build(Environment environment, String name, String userAgent) {
-		Client client = new JerseyClientBuilder(environment).using(jerseyClientConfiguration).build(name).register(MultiPartFeature.class);
-		return StringUtils.isNotEmpty(host) ?
-				new RESTService(client, getURL(), userAgent) : new RESTService(client, userAgent);
-	}
-
-	private String getURL() {
-		return String.format("%s://%s:%d", protocol, host, port);
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/ApiCallbacks.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/ApiCallbacks.java
deleted file mode 100644
index a1dd121..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/ApiCallbacks.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.rest.contracts;
-
-public class ApiCallbacks {
-	public static final String API = "/api";
-	public static final String KEY_LOADER = API + "/user/access_key/callback";
-	public static final String INFRASTRUCTURE_PROVISION = API + "/infrastructure_provision";
-	public static final String COMPUTATIONAL = INFRASTRUCTURE_PROVISION + "/computational_resources";
-	public static final String EXPLORATORY = INFRASTRUCTURE_PROVISION + "/exploratory_environment";
-	public static final String LIBRARY = INFRASTRUCTURE_PROVISION + "/library";
-	public static final String UPDATE_LIBS_URI = LIBRARY + "/update_lib_list";
-	public static final String INFRASTRUCTURE = API + "/infrastructure";
-	public static final String EDGE = INFRASTRUCTURE + "/edge";
-	public static final String STATUS_URI = "/status";
-	public static final String LIB_STATUS_URI = LIBRARY + "/lib_status";
-	public static final String GIT_CREDS = API + "/user/git_creds" + STATUS_URI;
-	public static final String IMAGE = INFRASTRUCTURE_PROVISION + "/image";
-	public static final String IMAGE_STATUS_URI = IMAGE + "/image_status";
-	public static final String BACKUP_URI = API + "/infrastructure/backup" + STATUS_URI;
-	public static final String REUPLOAD_KEY_URI = API + "/infrastructure/reupload_key/callback";
-	public static final String CHECK_INACTIVITY_EXPLORATORY_URI = API + "/infrastructure/inactivity/callback/exploratory";
-	public static final String CHECK_INACTIVITY_COMPUTATIONAL_URI = API + "/infrastructure/inactivity/callback" +
-			"/computational";
-
-	private ApiCallbacks() {
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/BackupAPI.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/BackupAPI.java
deleted file mode 100644
index 8217089..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/BackupAPI.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.rest.contracts;
-
-public class BackupAPI {
-	public static final String BACKUP = "backup";
-
-	private BackupAPI(){}
-}
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
deleted file mode 100644
index 2c152a4..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/ComputationalAPI.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.rest.contracts;
-
-public interface ComputationalAPI {
-	String AUDIT_MESSAGE = "Notebook name %s";
-	String AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE = "Reconfigure compute %s, requested for notebook %s";
-	String LIBRARY = "library/";
-	String COMPUTATIONAL = "computational";
-	String COMPUTATIONAL_CREATE = COMPUTATIONAL + "/create";
-	String COMPUTATIONAL_STOP = COMPUTATIONAL + "/stop";
-	String COMPUTATIONAL_START = COMPUTATIONAL + "/start";
-	String SPARK = "/spark";
-	String COMPUTATIONAL_CREATE_SPARK = COMPUTATIONAL_CREATE + SPARK;
-	String COMPUTATIONAL_RECONFIGURE_SPARK = COMPUTATIONAL + SPARK + "/reconfigure";
-	String COMPUTATIONAL_CREATE_CLOUD_SPECIFIC = COMPUTATIONAL_CREATE + "/cloud";
-	String COMPUTATIONAL_TERMINATE = COMPUTATIONAL + "/terminate";
-	String COMPUTATIONAL_TERMINATE_SPARK = COMPUTATIONAL_TERMINATE + SPARK;
-	String COMPUTATIONAL_STOP_SPARK = COMPUTATIONAL_STOP + SPARK;
-	String COMPUTATIONAL_START_SPARK = COMPUTATIONAL_START + SPARK;
-	String COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC = COMPUTATIONAL_TERMINATE + "/cloud";
-	String COMPUTATIONAL_LIB_INSTALL = LIBRARY + COMPUTATIONAL + "/lib_install";
-	String COMPUTATIONAL_LIB_LIST = LIBRARY + COMPUTATIONAL + "/lib_list";
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/DockerAPI.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/DockerAPI.java
deleted file mode 100644
index 4fe59a2..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/DockerAPI.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.rest.contracts;
-
-public interface DockerAPI {
-    String DOCKER = "docker";
-    String DOCKER_RUN = DOCKER + "/run";
-    String DOCKER_EXPLORATORY = DOCKER + "/exploratory";
-    String DOCKER_COMPUTATIONAL = DOCKER + "/computational";
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/ExploratoryAPI.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/ExploratoryAPI.java
deleted file mode 100644
index 0191a20..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/ExploratoryAPI.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.rest.contracts;
-
-public interface ExploratoryAPI {
-    String LIBRARY = "library/";
-    String EXPLORATORY = "exploratory";
-    String EXPLORATORY_CREATE = EXPLORATORY + "/create";
-    String EXPLORATORY_RECONFIGURE_SPARK = EXPLORATORY + "/reconfigure_spark";
-    String EXPLORATORY_START = EXPLORATORY + "/start";
-    String EXPLORATORY_TERMINATE = EXPLORATORY + "/terminate";
-    String EXPLORATORY_STOP = EXPLORATORY + "/stop";
-    String EXPLORATORY_LIB_INSTALL = LIBRARY + EXPLORATORY + "/lib_install";
-    String EXPLORATORY_LIB_LIST = LIBRARY + EXPLORATORY + "/lib_list";
-    String EXPLORATORY_GIT_CREDS = EXPLORATORY + "/git_creds";
-    String EXPLORATORY_IMAGE = EXPLORATORY + "/image";
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/InfrasctructureAPI.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/InfrasctructureAPI.java
deleted file mode 100644
index 38bf959..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/InfrasctructureAPI.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.rest.contracts;
-
-public final class InfrasctructureAPI {
-	public static final String INFRASTRUCTURE = "infrastructure";
-	public static final String INFRASTRUCTURE_STATUS = INFRASTRUCTURE + "/status";
-	public static final String EXPLORATORY_CHECK_INACTIVITY = INFRASTRUCTURE + "/exploratory/check_inactivity";
-	public static final String COMPUTATIONAL_CHECK_INACTIVITY = INFRASTRUCTURE + "/computational/check_inactivity";
-
-	private InfrasctructureAPI() {
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/KeyAPI.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/KeyAPI.java
deleted file mode 100644
index d93d440..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/KeyAPI.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.rest.contracts;
-
-public class KeyAPI {
-	public static final String REUPLOAD_KEY = "/key/reupload";
-	public static final String GET_ADMIN_KEY = "key";
-	public static final String KEY_EXTENTION = ".pub";
-
-	private KeyAPI() {
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/dto/ErrorDTO.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/dto/ErrorDTO.java
deleted file mode 100644
index c800c9b..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/dto/ErrorDTO.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.rest.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-public class ErrorDTO {
-
-	@JsonProperty
-	private final int code;
-	@JsonProperty
-	private final String message;
-
-	public ErrorDTO(int code, String message) {
-		this.code = code;
-		this.message = message;
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/AuthenticationExceptionMapper.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/AuthenticationExceptionMapper.java
deleted file mode 100644
index db2bc61..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/AuthenticationExceptionMapper.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.rest.mappers;
-
-import com.epam.dlab.exceptions.DlabAuthenticationException;
-import com.epam.dlab.rest.dto.ErrorDTO;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-public class AuthenticationExceptionMapper implements ExceptionMapper<DlabAuthenticationException> {
-	@Override
-	public Response toResponse(DlabAuthenticationException exception) {
-		final Response.Status unauthorized = Response.Status.UNAUTHORIZED;
-		return Response.status(unauthorized)
-				.entity(new ErrorDTO(unauthorized.getStatusCode(), exception.getMessage()))
-				.type(MediaType.APPLICATION_JSON)
-				.build();
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/DlabValidationExceptionMapper.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/DlabValidationExceptionMapper.java
deleted file mode 100644
index f3ce67f..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/DlabValidationExceptionMapper.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.rest.mappers;
-
-import com.epam.dlab.exceptions.DlabValidationException;
-import com.epam.dlab.rest.dto.ErrorDTO;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-public class DlabValidationExceptionMapper implements ExceptionMapper<DlabValidationException> {
-	@Override
-	public Response toResponse(DlabValidationException exception) {
-		final Response.Status badRequest = Response.Status.BAD_REQUEST;
-		return Response.status(badRequest)
-				.entity(new ErrorDTO(badRequest.getStatusCode(), exception.getMessage()))
-				.type(MediaType.APPLICATION_JSON)
-				.build();
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/GenericExceptionMapper.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/GenericExceptionMapper.java
deleted file mode 100644
index bd12539..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/GenericExceptionMapper.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.rest.mappers;
-
-import com.epam.dlab.rest.dto.ErrorDTO;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-public abstract class GenericExceptionMapper<E extends Exception> implements ExceptionMapper<E> {
-	static final Logger LOGGER = LoggerFactory.getLogger(GenericExceptionMapper.class);
-
-	@Override
-	public Response toResponse(E exception) {
-		LOGGER.error("Uncaught exception in application", exception);
-
-		return Response
-				.serverError()
-				.entity(new ErrorDTO(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), exception.getMessage()))
-				.type(MediaType.APPLICATION_JSON)
-				.build();
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/JsonProcessingExceptionMapper.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/JsonProcessingExceptionMapper.java
deleted file mode 100644
index 24cf850..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/JsonProcessingExceptionMapper.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.rest.mappers;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-
-import javax.ws.rs.ext.Provider;
-
-@Provider
-public class JsonProcessingExceptionMapper extends GenericExceptionMapper<JsonProcessingException> {
-}
\ No newline at end of file
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ResourceConflictExceptionMapper.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ResourceConflictExceptionMapper.java
deleted file mode 100644
index 1f4e35e..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ResourceConflictExceptionMapper.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.rest.mappers;
-
-import com.epam.dlab.exceptions.ResourceConflictException;
-import com.epam.dlab.rest.dto.ErrorDTO;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-@Provider
-public class ResourceConflictExceptionMapper implements ExceptionMapper<ResourceConflictException> {
-	@Override
-	public Response toResponse(ResourceConflictException e) {
-		final Response.Status conflict = Response.Status.CONFLICT;
-		return Response.status(conflict)
-				.type(MediaType.APPLICATION_JSON)
-				.entity(new ErrorDTO(conflict.getStatusCode(), e.getMessage()))
-				.build();
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ResourceNotFoundExceptionMapper.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ResourceNotFoundExceptionMapper.java
deleted file mode 100644
index d98a57f..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ResourceNotFoundExceptionMapper.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.rest.mappers;
-
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.rest.dto.ErrorDTO;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-@Provider
-public class ResourceNotFoundExceptionMapper implements ExceptionMapper<ResourceNotFoundException> {
-	@Override
-	public Response toResponse(ResourceNotFoundException e) {
-		final Response.Status notFound = Response.Status.NOT_FOUND;
-		return Response.status(notFound)
-				.type(MediaType.APPLICATION_JSON)
-				.entity(new ErrorDTO(notFound.getStatusCode(), e.getMessage()))
-				.build();
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ResourceQuoteReachedExceptionMapper.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ResourceQuoteReachedExceptionMapper.java
deleted file mode 100644
index 7a60907..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ResourceQuoteReachedExceptionMapper.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.rest.mappers;
-
-import com.epam.dlab.exceptions.ResourceQuoteReachedException;
-import com.epam.dlab.rest.dto.ErrorDTO;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-public class ResourceQuoteReachedExceptionMapper implements ExceptionMapper<ResourceQuoteReachedException> {
-	@Override
-	public Response toResponse(ResourceQuoteReachedException exception) {
-		final Response.Status forbidden = Response.Status.FORBIDDEN;
-		return Response.status(forbidden)
-				.type(MediaType.APPLICATION_JSON_TYPE)
-				.entity(new ErrorDTO(forbidden.getStatusCode(), exception.getMessage()))
-				.build();
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/RuntimeExceptionMapper.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/RuntimeExceptionMapper.java
deleted file mode 100644
index e2eaa4d..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/RuntimeExceptionMapper.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.rest.mappers;
-
-import com.epam.dlab.rest.dto.ErrorDTO;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.Provider;
-
-@Provider
-@Slf4j
-public class RuntimeExceptionMapper extends GenericExceptionMapper<RuntimeException> {
-
-	@Override
-	public Response toResponse(RuntimeException exception) {
-		if (exception instanceof WebApplicationException) {
-			return handleWebApplicationException(exception);
-		}
-		return super.toResponse(exception);
-	}
-
-	private Response handleWebApplicationException(RuntimeException exception) {
-		WebApplicationException webAppException = (WebApplicationException) exception;
-
-		if (webAppException.getResponse().getStatusInfo() == Response.Status.UNAUTHORIZED
-				|| webAppException.getResponse().getStatusInfo() == Response.Status.FORBIDDEN) {
-
-			return web(exception, Response.Status.UNAUTHORIZED);
-		} else if (webAppException.getResponse().getStatusInfo() == Response.Status.NOT_FOUND) {
-			return web(exception, Response.Status.NOT_FOUND);
-		}
-
-		return super.toResponse(exception);
-	}
-
-	private Response web(RuntimeException exception, Response.StatusType status) {
-		log.error("Web application exception: {}", exception.getMessage(), exception);
-		return Response.status(status)
-				.type(MediaType.APPLICATION_JSON)
-				.entity(new ErrorDTO(status.getStatusCode(), exception.getMessage()))
-				.build();
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ValidationExceptionMapper.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ValidationExceptionMapper.java
deleted file mode 100644
index 700ce4d..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ValidationExceptionMapper.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.rest.mappers;
-
-import com.epam.dlab.rest.dto.ErrorDTO;
-import io.dropwizard.jersey.validation.ConstraintMessage;
-import io.dropwizard.jersey.validation.JerseyViolationException;
-import org.glassfish.jersey.server.model.Invocable;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import java.util.stream.Collectors;
-
-public class ValidationExceptionMapper implements ExceptionMapper<JerseyViolationException> {
-	@Override
-	public Response toResponse(JerseyViolationException exception) {
-		Invocable invocable = exception.getInvocable();
-		final String errors =
-				exception.getConstraintViolations()
-						.stream().map(violation -> ConstraintMessage.getMessage(violation, invocable))
-						.collect(Collectors.joining(","));
-		return Response.status(Response.Status.BAD_REQUEST)
-				.entity(new ErrorDTO(Response.Status.BAD_REQUEST.getStatusCode(), errors))
-				.type(MediaType.APPLICATION_JSON)
-				.build();
-	}
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/validation/AwsValidation.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/validation/AwsValidation.java
deleted file mode 100644
index 715f27f..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/validation/AwsValidation.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.validation;
-
-public interface AwsValidation {
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/validation/AzureValidation.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/validation/AzureValidation.java
deleted file mode 100644
index 14ec7d5..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/validation/AzureValidation.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.validation;
-
-public interface AzureValidation {
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/validation/CloudConfigurationSequenceProvider.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/validation/CloudConfigurationSequenceProvider.java
deleted file mode 100644
index 37503f4..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/validation/CloudConfigurationSequenceProvider.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.validation;
-
-import com.epam.dlab.ServiceConfiguration;
-import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;
-
-import java.lang.reflect.ParameterizedType;
-import java.util.ArrayList;
-import java.util.List;
-
-public class CloudConfigurationSequenceProvider<T extends ServiceConfiguration> implements DefaultGroupSequenceProvider<T> {
-    @Override
-    public List<Class<?>> getValidationGroups(T c) {
-        List<Class<?>> sequence = new ArrayList<>();
-
-        sequence.add(initialSequenceGroup());
-
-        if (c == null) {
-            return sequence;
-        } else {
-            switch (c.getCloudProvider()) {
-                case AWS:
-                    sequence.add(AwsValidation.class);
-                    break;
-                case AZURE:
-                    sequence.add(AzureValidation.class);
-                    break;
-                case GCP:
-                    sequence.add(GcpValidation.class);
-                    break;
-                default:
-                    throw new IllegalArgumentException("Cloud provider is not supported" + c.getCloudProvider());
-            }
-        }
-
-        return sequence;
-    }
-
-    private Class<T> initialSequenceGroup() {
-        ParameterizedType parameterizedType = (ParameterizedType) getClass()
-                .getGenericSuperclass();
-
-        @SuppressWarnings("unchecked")
-        Class<T> ret = (Class<T>) parameterizedType.getActualTypeArguments()[0];
-
-        return ret;
-    }
-}
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/validation/GcpValidation.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/validation/GcpValidation.java
deleted file mode 100644
index b2e2435..0000000
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/validation/GcpValidation.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.validation;
-
-public interface GcpValidation {
-}
diff --git a/services/provisioning-service/pom.xml b/services/provisioning-service/pom.xml
index 0b62c36..055bbe7 100644
--- a/services/provisioning-service/pom.xml
+++ b/services/provisioning-service/pom.xml
@@ -21,8 +21,8 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
-        <groupId>com.epam.dlab</groupId>
-        <artifactId>dlab</artifactId>
+        <groupId>com.epam.datalab</groupId>
+        <artifactId>datalab</artifactId>
         <version>1.0</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
@@ -50,7 +50,7 @@
 
     <dependencies>
         <dependency>
-            <groupId>com.epam.dlab</groupId>
+            <groupId>com.epam.datalab</groupId>
             <artifactId>common</artifactId>
         </dependency>
         <dependency>
@@ -63,18 +63,18 @@
             <artifactId>dropwizard-template-config</artifactId>
         </dependency>
         <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>dlab-model</artifactId>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>datalab-model</artifactId>
             <version>${project.parent.version}</version>
         </dependency>
         <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>dlab-utils</artifactId>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>datalab-utils</artifactId>
             <version>${project.parent.version}</version>
         </dependency>
         <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>dlab-webapp-common</artifactId>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>datalab-webapp-common</artifactId>
             <version>${project.parent.version}</version>
         </dependency>
         <dependency>
@@ -162,12 +162,12 @@
                                         implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                                 <transformer
                                         implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
-                                    <mainClass>com.epam.dlab.backendapi.ProvisioningServiceApplication</mainClass>
+                                    <mainClass>com.epam.datalab.backendapi.ProvisioningServiceApplication</mainClass>
                                     <manifestEntries>
                                         <Created-By>&lt;EPAM&gt; Systems</Created-By>
-                                        <Name>com/epam/dlab</Name>
-                                        <Implementation-Title>DLab Provisioning Service</Implementation-Title>
-                                        <Implementation-Version>${dlab.version}</Implementation-Version>
+                                        <Name>com/epam/datalab</Name>
+                                        <Implementation-Title>DataLab Provisioning Service</Implementation-Title>
+                                        <Implementation-Version>${datalab.version}</Implementation-Version>
                                         <Implementation-Vendor>&lt;EPAM&gt; Systems</Implementation-Vendor>
                                         <Build-Time>${maven.build.timestamp}</Build-Time>
                                         <Build-OS>${os.name}</Build-OS>
@@ -188,9 +188,9 @@
                         <exclude>**/*Configuration.*</exclude>
                         <exclude>**/*Module.*</exclude>
                         <exclude>**/*Form.*</exclude>
-                        <exclude>com/epam/dlab/process/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/modules/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/validation/**/*</exclude>
+                        <exclude>com/epam/datalab/process/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/modules/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/validation/**/*</exclude>
                     </excludes>
                 </configuration>
             </plugin>
diff --git a/services/provisioning-service/provisioning.yml b/services/provisioning-service/provisioning.yml
index 5ddbc62..b6ced32 100644
--- a/services/provisioning-service/provisioning.yml
+++ b/services/provisioning-service/provisioning.yml
@@ -19,23 +19,23 @@
 #
 # ******************************************************************************
 
-<#include "ssn.yml">
+  <#include "ssn.yml">
 
-backupScriptPath: /opt/dlab/tmp/backup.py
-backupDirectory: /opt/dlab/tmp/result
+backupScriptPath: /opt/datalab/tmp/backup.py
+backupDirectory: /opt/datalab/tmp/result
 keyDirectory: ${KEYS_DIR}
-responseDirectory: /opt/dlab/tmp
-handlerDirectory: /opt/dlab/handlers
+responseDirectory: /opt/datalab/tmp
+handlerDirectory: /opt/datalab/handlers
 dockerLogDirectory: ${LOG_ROOT_DIR}
 warmupPollTimeout: 2m
 resourceStatusPollTimeout: 400m
 keyLoaderPollTimeout: 30m
 requestEnvStatusTimeout: 50s
 adminKey: KEYNAME
-edgeImage: docker.dlab-edge
+edgeImage: docker.datalab-edge
 fileLengthCheckDelay: 500ms
 
-<#if CLOUD_TYPE == "aws">
+  <#if CLOUD_TYPE == "aws">
 emrEC2RoleDefault: EMR_EC2_DefaultRole
 emrServiceRoleDefault: EMR_DefaultRole
 </#if>
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/DropwizardBearerTokenFilterImpl.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/DropwizardBearerTokenFilterImpl.java
new file mode 100644
index 0000000..d0a36ba
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/DropwizardBearerTokenFilterImpl.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.datalab.backendapi;
+
+import org.keycloak.adapters.AdapterDeploymentContext;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.NodesRegistrationManagement;
+import org.keycloak.jaxrs.JaxrsBearerTokenFilterImpl;
+
+import javax.annotation.Priority;
+import javax.ws.rs.Priorities;
+import javax.ws.rs.container.PreMatching;
+
+@PreMatching
+@Priority(Priorities.AUTHENTICATION)
+public class DropwizardBearerTokenFilterImpl extends JaxrsBearerTokenFilterImpl {
+
+    public DropwizardBearerTokenFilterImpl(KeycloakDeployment keycloakDeployment) {
+        deploymentContext = new AdapterDeploymentContext(keycloakDeployment);
+        nodesRegistrationManagement = new NodesRegistrationManagement();
+    }
+}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/ProvisioningServiceApplication.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/ProvisioningServiceApplication.java
new file mode 100644
index 0000000..fa24201
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/ProvisioningServiceApplication.java
@@ -0,0 +1,161 @@
+/*
+ * 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.datalab.backendapi;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.DirectoriesCreator;
+import com.epam.datalab.backendapi.core.DockerWarmuper;
+import com.epam.datalab.backendapi.core.response.handlers.ComputationalConfigure;
+import com.epam.datalab.backendapi.modules.CloudModuleConfigurator;
+import com.epam.datalab.backendapi.modules.ModuleFactory;
+import com.epam.datalab.backendapi.resources.BackupResource;
+import com.epam.datalab.backendapi.resources.BucketResource;
+import com.epam.datalab.backendapi.resources.CallbackHandlerResource;
+import com.epam.datalab.backendapi.resources.DockerResource;
+import com.epam.datalab.backendapi.resources.GitExploratoryResource;
+import com.epam.datalab.backendapi.resources.ImageResource;
+import com.epam.datalab.backendapi.resources.InfrastructureResource;
+import com.epam.datalab.backendapi.resources.LibraryResource;
+import com.epam.datalab.backendapi.resources.ProjectResource;
+import com.epam.datalab.backendapi.resources.ProvisioningHealthCheckResource;
+import com.epam.datalab.backendapi.resources.base.KeyResource;
+import com.epam.datalab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
+import com.epam.datalab.cloud.CloudModule;
+import com.epam.datalab.process.model.DatalabProcess;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.mappers.JsonProcessingExceptionMapper;
+import com.epam.datalab.rest.mappers.RuntimeExceptionMapper;
+import com.epam.datalab.util.ServiceUtils;
+import com.fasterxml.jackson.databind.InjectableValues;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import de.ahus1.keycloak.dropwizard.AbstractKeycloakAuthenticator;
+import de.ahus1.keycloak.dropwizard.KeycloakBundle;
+import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
+import de.thomaskrille.dropwizard_template_config.TemplateConfigBundle;
+import de.thomaskrille.dropwizard_template_config.TemplateConfigBundleConfiguration;
+import io.dropwizard.Application;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.Authorizer;
+import io.dropwizard.forms.MultiPartBundle;
+import io.dropwizard.jersey.setup.JerseyEnvironment;
+import io.dropwizard.setup.Bootstrap;
+import io.dropwizard.setup.Environment;
+import org.keycloak.KeycloakSecurityContext;
+
+import javax.servlet.http.HttpServletRequest;
+import java.security.Principal;
+
+public class ProvisioningServiceApplication extends Application<ProvisioningServiceApplicationConfiguration> {
+
+    public static void main(String[] args) throws Exception {
+        if (ServiceUtils.printAppVersion(ProvisioningServiceApplication.class, args)) {
+            return;
+        }
+        new ProvisioningServiceApplication().run(args);
+    }
+
+    @Override
+    public void initialize(Bootstrap<ProvisioningServiceApplicationConfiguration> bootstrap) {
+        bootstrap.addBundle(new MultiPartBundle());
+        bootstrap.addBundle(new TemplateConfigBundle(
+                new TemplateConfigBundleConfiguration().fileIncludePath(ServiceUtils.getConfPath())
+        ));
+        bootstrap.addBundle(new KeycloakBundle<ProvisioningServiceApplicationConfiguration>() {
+            @Override
+            protected KeycloakConfiguration getKeycloakConfiguration(ProvisioningServiceApplicationConfiguration configuration) {
+                return configuration.getKeycloakConfiguration();
+            }
+
+            @Override
+            protected Class<? extends Principal> getUserClass() {
+                return UserInfo.class;
+            }
+
+            @Override
+            protected Authorizer createAuthorizer() {
+                return (Authorizer<UserInfo>) (principal, role) -> principal.getRoles().contains(role);
+            }
+
+            @Override
+            protected Authenticator createAuthenticator(KeycloakConfiguration configuration) {
+                class KeycloakAuthenticator extends AbstractKeycloakAuthenticator<UserInfo> {
+
+                    private KeycloakAuthenticator(KeycloakConfiguration keycloakConfiguration) {
+                        super(keycloakConfiguration);
+                    }
+
+                    @Override
+                    protected UserInfo prepareAuthentication(KeycloakSecurityContext keycloakSecurityContext,
+                                                             HttpServletRequest httpServletRequest,
+                                                             KeycloakConfiguration keycloakConfiguration) {
+                        return new UserInfo(keycloakSecurityContext.getToken().getPreferredUsername(),
+                                keycloakSecurityContext.getIdTokenString());
+                    }
+                }
+                return new KeycloakAuthenticator(configuration);
+            }
+        });
+    }
+
+    @Override
+    public void run(ProvisioningServiceApplicationConfiguration configuration, Environment environment) {
+        DatalabProcess.getInstance().setProcessTimeout(configuration.getProcessTimeout());
+        DatalabProcess.getInstance().setMaxProcessesPerBox(configuration.getProcessMaxThreadsPerJvm());
+        DatalabProcess.getInstance().setMaxProcessesPerUser(configuration.getProcessMaxThreadsPerUser());
+
+        CloudModule cloudModule = CloudModuleConfigurator.getCloudModule(configuration);
+        Injector injector = Guice.createInjector(ModuleFactory.getModule(configuration, environment), cloudModule);
+        cloudModule.init(environment, injector);
+
+
+        final ObjectMapper mapper = injector.getInstance(ObjectMapper.class);
+        final InjectableValues.Std injectableValues = new InjectableValues.Std();
+        injectableValues.addValue(RESTService.class, injector.getInstance(RESTService.class));
+        injectableValues.addValue(ComputationalConfigure.class, injector.getInstance(ComputationalConfigure.class));
+        mapper.setInjectableValues(injectableValues);
+
+        environment.lifecycle().manage(injector.getInstance(DirectoriesCreator.class));
+        if (configuration.isHandlersPersistenceEnabled()) {
+            environment.lifecycle().manage(injector.getInstance(RestoreCallbackHandlerServiceImpl.class));
+        }
+        environment.lifecycle().manage(injector.getInstance(DockerWarmuper.class));
+
+
+        JerseyEnvironment jersey = environment.jersey();
+        jersey.register(configuration.getCloudProvider());
+        jersey.register(new RuntimeExceptionMapper());
+        jersey.register(new JsonProcessingExceptionMapper());
+
+        jersey.register(injector.getInstance(DockerResource.class));
+        jersey.register(injector.getInstance(GitExploratoryResource.class));
+        jersey.register(injector.getInstance(LibraryResource.class));
+        jersey.register(injector.getInstance(InfrastructureResource.class));
+        jersey.register(injector.getInstance(ImageResource.class));
+        jersey.register(injector.getInstance(BackupResource.class));
+        jersey.register(injector.getInstance(KeyResource.class));
+        jersey.register(injector.getInstance(CallbackHandlerResource.class));
+        jersey.register(injector.getInstance(ProjectResource.class));
+        jersey.register(injector.getInstance(ProvisioningHealthCheckResource.class));
+        environment.jersey().register(injector.getInstance(BucketResource.class));
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/ProvisioningServiceApplicationConfiguration.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/ProvisioningServiceApplicationConfiguration.java
new file mode 100644
index 0000000..25bdfcc
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/ProvisioningServiceApplicationConfiguration.java
@@ -0,0 +1,197 @@
+/*
+ * 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.datalab.backendapi;
+
+import com.epam.datalab.ServiceConfiguration;
+import com.epam.datalab.backendapi.conf.CloudConfiguration;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.validation.ProvisioningServiceCloudConfigurationSequenceProvider;
+import com.epam.datalab.validation.AwsValidation;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
+import io.dropwizard.util.Duration;
+import org.hibernate.validator.constraints.NotEmpty;
+import org.hibernate.validator.group.GroupSequenceProvider;
+
+@GroupSequenceProvider(ProvisioningServiceCloudConfigurationSequenceProvider.class)
+public class ProvisioningServiceApplicationConfiguration extends ServiceConfiguration implements Directories {
+
+    @NotEmpty
+    @JsonProperty
+    private String keyDirectory;
+
+    @NotEmpty
+    @JsonProperty
+    private String responseDirectory;
+
+    @NotEmpty
+    @JsonProperty
+    private String dockerLogDirectory;
+
+    @NotEmpty
+    @JsonProperty
+    private String handlerDirectory;
+
+    @JsonProperty
+    private Duration warmupPollTimeout;
+
+    @JsonProperty
+    private Duration resourceStatusPollTimeout = Duration.minutes(3);
+
+    @JsonProperty
+    private Duration keyLoaderPollTimeout = Duration.minutes(2);
+
+    @JsonProperty
+    private Duration requestEnvStatusTimeout = Duration.seconds(30);
+
+    @NotEmpty
+    @JsonProperty
+    private String adminKey;
+
+    @NotEmpty
+    @JsonProperty
+    private String edgeImage;
+
+    @JsonProperty
+    private Duration fileLengthCheckDelay = Duration.seconds(3);
+
+    @NotEmpty(groups = AwsValidation.class)
+    @JsonProperty
+    private String emrEC2RoleDefault;
+
+    @NotEmpty(groups = AwsValidation.class)
+    @JsonProperty
+    private String emrServiceRoleDefault;
+
+    @JsonProperty
+    private int processMaxThreadsPerJvm = 50;
+
+    @JsonProperty
+    private int processMaxThreadsPerUser = 5;
+
+    @JsonProperty
+    private Duration processTimeout = Duration.hours(3);
+    @JsonProperty
+    private String backupScriptPath;
+    @JsonProperty
+    private String backupDirectory;
+    @JsonProperty
+    private boolean handlersPersistenceEnabled;
+
+    private KeycloakConfiguration keycloakConfiguration = new KeycloakConfiguration();
+
+    @JsonProperty("cloudProperties")
+    private CloudConfiguration cloudConfiguration;
+
+    public boolean isHandlersPersistenceEnabled() {
+        return handlersPersistenceEnabled;
+    }
+
+    public String getKeyDirectory() {
+        return keyDirectory;
+    }
+
+    public Duration getWarmupPollTimeout() {
+        return warmupPollTimeout;
+    }
+
+    public Duration getResourceStatusPollTimeout() {
+        return resourceStatusPollTimeout;
+    }
+
+    public Duration getKeyLoaderPollTimeout() {
+        return keyLoaderPollTimeout;
+    }
+
+    /**
+     * Return the timeout for the check the status of environment resources.
+     */
+    public Duration getRequestEnvStatusTimeout() {
+        return requestEnvStatusTimeout;
+    }
+
+    public String getAdminKey() {
+        return adminKey;
+    }
+
+    public String getEdgeImage() {
+        return edgeImage;
+    }
+
+    public Duration getFileLengthCheckDelay() {
+        return fileLengthCheckDelay;
+    }
+
+    public String getEmrEC2RoleDefault() {
+        return emrEC2RoleDefault;
+    }
+
+    public String getEmrServiceRoleDefault() {
+        return emrServiceRoleDefault;
+    }
+
+    public String getWarmupDirectory() {
+        return responseDirectory + WARMUP_DIRECTORY;
+    }
+
+    public String getImagesDirectory() {
+        return responseDirectory + IMAGES_DIRECTORY;
+    }
+
+    public String getKeyLoaderDirectory() {
+        return responseDirectory + KEY_LOADER_DIRECTORY;
+    }
+
+    public String getDockerLogDirectory() {
+        return dockerLogDirectory;
+    }
+
+    public int getProcessMaxThreadsPerJvm() {
+        return processMaxThreadsPerJvm;
+    }
+
+    public int getProcessMaxThreadsPerUser() {
+        return processMaxThreadsPerUser;
+    }
+
+    public Duration getProcessTimeout() {
+        return processTimeout;
+    }
+
+    public String getBackupScriptPath() {
+        return backupScriptPath;
+    }
+
+    public String getBackupDirectory() {
+        return backupDirectory;
+    }
+
+    public String getHandlerDirectory() {
+        return handlerDirectory;
+    }
+
+    public KeycloakConfiguration getKeycloakConfiguration() {
+        return keycloakConfiguration;
+    }
+
+    public CloudConfiguration getCloudConfiguration() {
+        return cloudConfiguration;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/conf/CloudConfiguration.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/conf/CloudConfiguration.java
new file mode 100644
index 0000000..1e90716
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/conf/CloudConfiguration.java
@@ -0,0 +1,83 @@
+/*
+ * 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.datalab.backendapi.conf;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class CloudConfiguration {
+
+    private final String os;
+    private final String serviceBaseName;
+    private final String edgeInstanceSize;
+    private final String subnetId;
+    private final String region;
+    private final String zone;
+    private final String confTagResourceId;
+    private final String securityGroupIds;
+    private final String ssnInstanceSize;
+    private final String notebookVpcId;
+    private final String notebookSubnetId;
+    private final String confKeyDir;
+    private final String vpcId;
+    private final String azureResourceGroupName;
+    private final String ssnStorageAccountTagName;
+    private final String sharedStorageAccountTagName;
+    private final String datalakeTagName;
+    private final String azureAuthFile;
+    private final String azureClientId;
+    private final String peeringId;
+    private final String gcpProjectId;
+    private final boolean imageEnabled;
+    @JsonProperty("ldap")
+    private final LdapConfig ldapConfig;
+    private final StepCerts stepCerts;
+    private final Keycloak keycloak;
+
+    @Data
+    public static class LdapConfig {
+        private final String host;
+        private final String dn;
+        private final String ou;
+        private final String user;
+        private final String password;
+    }
+
+    @Data
+    public static class StepCerts {
+        private final boolean enabled;
+        private final String rootCA;
+        private final String kid;
+        private final String kidPassword;
+        private final String caURL;
+    }
+
+    @Data
+    public static class Keycloak {
+        @JsonProperty("auth_server_url")
+        private final String authServerUrl;
+        @JsonProperty("realm_name")
+        private final String realmName;
+        private final String user;
+        @JsonProperty("user_password")
+        private final String userPassword;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/Constants.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/Constants.java
new file mode 100644
index 0000000..04cf0d4
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/Constants.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab.backendapi.core;
+
+public class Constants {
+
+    public static final String JSON_EXTENSION = ".json";
+    public static final String LOG_EXTENSION = ".log";
+
+    private Constants() {
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/Directories.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/Directories.java
new file mode 100644
index 0000000..d281ee8
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/Directories.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.datalab.backendapi.core;
+
+public interface Directories {
+    String WARMUP_DIRECTORY = "/result";
+    String IMAGES_DIRECTORY = "/result";
+    String KEY_LOADER_DIRECTORY = "/result";
+    String EDGE_LOG_DIRECTORY = "edge";
+    String NOTEBOOK_LOG_DIRECTORY = "notebook";
+    String DATA_ENGINE_LOG_DIRECTORY = "dataengine";
+    String DATA_ENGINE_SERVICE_LOG_DIRECTORY = "dataengine-service";
+    String IMAGE_LOG_DIRECTORY = "image";
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/DirectoriesCreator.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/DirectoriesCreator.java
new file mode 100644
index 0000000..40da2c2
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/DirectoriesCreator.java
@@ -0,0 +1,49 @@
+/*
+ * 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.datalab.backendapi.core;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import io.dropwizard.lifecycle.Managed;
+
+import java.io.File;
+
+@Singleton
+public class DirectoriesCreator implements Managed {
+    @Inject
+    private ProvisioningServiceApplicationConfiguration configuration;
+
+    @Override
+    public void start() throws Exception {
+        createDirectory(configuration.getWarmupDirectory());
+        createDirectory(configuration.getImagesDirectory());
+        createDirectory(configuration.getKeyLoaderDirectory());
+        createDirectory(configuration.getHandlerDirectory());
+    }
+
+    private boolean createDirectory(String directory) {
+        return new File(directory).mkdirs();
+    }
+
+    @Override
+    public void stop() throws Exception {
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/DockerWarmuper.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/DockerWarmuper.java
new file mode 100644
index 0000000..58e0e9a
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/DockerWarmuper.java
@@ -0,0 +1,172 @@
+/*
+ * 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.datalab.backendapi.core;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.ICommandExecutor;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.folderlistener.FolderListenerExecutor;
+import com.epam.datalab.dto.imagemetadata.ComputationalMetadataDTO;
+import com.epam.datalab.dto.imagemetadata.ExploratoryMetadataDTO;
+import com.epam.datalab.dto.imagemetadata.ImageMetadataDTO;
+import com.epam.datalab.dto.imagemetadata.ImageType;
+import com.epam.datalab.process.model.ProcessInfo;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import io.dropwizard.lifecycle.Managed;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+
+@Singleton
+public class DockerWarmuper implements Managed, DockerCommands, MetadataHolder {
+	private static final Logger LOGGER = LoggerFactory.getLogger(DockerWarmuper.class);
+	public static final String EXPLORATORY_RESPONSE_MARKER = "exploratory_environment_shapes";
+
+	@Inject
+	private ProvisioningServiceApplicationConfiguration configuration;
+	@Inject
+	private FolderListenerExecutor folderListenerExecutor;
+	@Inject
+	private ICommandExecutor commandExecutor;
+	private Map<String, String> imageList = new ConcurrentHashMap<>();
+	private Set<ImageMetadataDTO> metadataDTOs = ConcurrentHashMap.newKeySet();
+
+
+	@Override
+	public void start() throws Exception {
+		LOGGER.debug("warming up docker");
+		final ProcessInfo processInfo = commandExecutor.executeSync("warmup", DockerCommands.generateUUID(),
+				GET_IMAGES);
+		List<String> images = Arrays.asList(processInfo.getStdOut().split("\n"));
+		for (String image : images) {
+			String uuid = UUID.randomUUID().toString();
+			LOGGER.debug("warming up image: {} with uid {}", image, uuid);
+			imageList.put(uuid, image);
+			folderListenerExecutor.start(configuration.getWarmupDirectory(),
+					configuration.getWarmupPollTimeout(),
+					getFileHandlerCallback(uuid));
+			String command = new RunDockerCommand()
+					.withVolumeForRootKeys(configuration.getKeyDirectory())
+					.withVolumeForResponse(configuration.getWarmupDirectory())
+					.withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
+					.withResource(getResourceType())
+					.withRequestId(uuid)
+					.withActionDescribe(image)
+					.toCMD();
+			commandExecutor.executeAsync("warmup", uuid, command);
+		}
+	}
+
+	public class DockerFileHandlerCallback implements FileHandlerCallback {
+		private final String uuid;
+
+		@JsonCreator
+		public DockerFileHandlerCallback(@JsonProperty("uuid") String uuid) {
+			this.uuid = uuid;
+		}
+
+		@Override
+		public String getUUID() {
+			return uuid;
+		}
+
+		@Override
+		public boolean checkUUID(String uuid) {
+			return this.uuid.equals(uuid);
+		}
+
+		@Override
+		public boolean handle(String fileName, byte[] content) {
+			String uuid = DockerCommands.extractUUID(fileName);
+			try {
+				LOGGER.debug("processing response file {} with content {}", fileName, new String(content));
+				addMetadata(content, uuid);
+			} catch (IOException e) {
+				LOGGER.error("processing response file {} fails", fileName, e);
+				return false;
+			}
+			return true;
+		}
+
+		@Override
+		public void handleError(String errorMessage) {
+			LOGGER.warn("docker warmupper returned no result: {}", errorMessage);
+		}
+
+		@Override
+		public String getUser() {
+			return "DATALAB";
+		}
+	}
+
+	public DockerFileHandlerCallback getFileHandlerCallback(String uuid) {
+		return new DockerFileHandlerCallback(uuid);
+	}
+
+	private void addMetadata(byte[] content, String uuid) throws IOException {
+		final JsonNode jsonNode = MAPPER.readTree(content);
+		ImageMetadataDTO metadata;
+		if (jsonNode.has(EXPLORATORY_RESPONSE_MARKER)) {
+			metadata = MAPPER.readValue(content, ExploratoryMetadataDTO.class);
+			metadata.setImageType(ImageType.EXPLORATORY);
+		} else {
+			metadata = MAPPER.readValue(content, ComputationalMetadataDTO.class);
+			metadata.setImageType(ImageType.COMPUTATIONAL);
+		}
+		String image = imageList.get(uuid);
+		metadata.setImage(image);
+		LOGGER.debug("caching metadata for image {}: {}", image, metadata);
+		metadataDTOs.add(metadata);
+	}
+
+	@Override
+	public void stop() throws Exception {
+		//do nothing
+	}
+
+	public Map<String, String> getUuids() {
+		return Collections.unmodifiableMap(imageList);
+	}
+
+	public Set<ImageMetadataDTO> getMetadata(ImageType type) {
+		return metadataDTOs.stream().filter(m -> m.getImageType().equals(type))
+				.collect(Collectors.toSet());
+	}
+
+	@Override
+	public String getResourceType() {
+		return Directories.NOTEBOOK_LOG_DIRECTORY;
+	}
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/FileHandlerCallback.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/FileHandlerCallback.java
new file mode 100644
index 0000000..bbcf771
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/FileHandlerCallback.java
@@ -0,0 +1,41 @@
+/*
+ * 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.datalab.backendapi.core;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@class")
+public interface FileHandlerCallback {
+    String getUUID();
+
+    boolean checkUUID(String uuid);
+
+    boolean handle(String fileName, byte[] content) throws Exception;
+
+    void handleError(String errorMessage);
+
+    String getUser();
+
+    @JsonIgnore
+    default String getId() {
+        return this.getClass().getSimpleName() + "_" + getUUID();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/MetadataHolder.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/MetadataHolder.java
new file mode 100644
index 0000000..3800313
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/MetadataHolder.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.datalab.backendapi.core;
+
+
+import com.epam.datalab.dto.imagemetadata.ImageMetadataDTO;
+import com.epam.datalab.dto.imagemetadata.ImageType;
+
+import java.util.Set;
+
+@FunctionalInterface
+public interface MetadataHolder {
+    Set<ImageMetadataDTO> getMetadata(ImageType metadataType);
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CmdCommand.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CmdCommand.java
new file mode 100644
index 0000000..16fdfce
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CmdCommand.java
@@ -0,0 +1,25 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+@FunctionalInterface
+public interface CmdCommand {
+    String toCMD();
+}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandBuilder.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandBuilder.java
new file mode 100644
index 0000000..f0a75eb
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandBuilder.java
@@ -0,0 +1,186 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.conf.CloudConfiguration;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.ResourceBaseDTO;
+import com.epam.datalab.dto.aws.AwsCloudSettings;
+import com.epam.datalab.dto.azure.AzureCloudSettings;
+import com.epam.datalab.dto.base.CloudSettings;
+import com.epam.datalab.dto.gcp.GcpCloudSettings;
+import com.epam.datalab.util.JsonGenerator;
+import com.epam.datalab.util.SecurityUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Singleton
+public class CommandBuilder {
+
+    private final ProvisioningServiceApplicationConfiguration conf;
+
+    @Inject
+    public CommandBuilder(ProvisioningServiceApplicationConfiguration conf) {
+        this.conf = conf;
+    }
+
+    public String buildCommand(RunDockerCommand runDockerCommand, ResourceBaseDTO<?> resourceBaseDTO) throws JsonProcessingException {
+        StringBuilder builder = new StringBuilder();
+        if (resourceBaseDTO != null) {
+            builder.append("echo -e '");
+            try {
+                resourceBaseDTO.setCloudSettings(getCloudSettings(resourceBaseDTO.getCloudSettings()));
+                String str = JsonGenerator.generateJson(resourceBaseDTO);
+                log.info("Serialized DTO to: {}", SecurityUtils.hideCreds(str));
+                builder.append(str);
+            } catch (JsonProcessingException e) {
+                log.error("ERROR generating json from dockerRunParameters: {}", e.getMessage());
+                throw e;
+            }
+            builder.append('\'');
+            builder.append(" | ");
+        }
+        builder.append(runDockerCommand.toCMD());
+        return builder.toString();
+    }
+
+    private CloudSettings getCloudSettings(CloudSettings settings) {
+        final CloudProvider cloudProvider = conf.getCloudProvider();
+        final CloudConfiguration cloudConfiguration = conf.getCloudConfiguration();
+        final CloudConfiguration.LdapConfig ldapConfig = cloudConfiguration.getLdapConfig();
+        final CloudConfiguration.StepCerts stepCerts = cloudConfiguration.getStepCerts();
+        final CloudConfiguration.Keycloak keycloak = cloudConfiguration.getKeycloak();
+        if (cloudProvider == CloudProvider.AWS) {
+            return awsCloudSettings(settings, cloudConfiguration, ldapConfig, stepCerts, keycloak);
+        } else if (cloudProvider == CloudProvider.GCP) {
+            return gcpCloudSettings(settings, cloudConfiguration, ldapConfig, stepCerts, keycloak);
+        } else if (cloudProvider == CloudProvider.AZURE) {
+            return azureCloudSettings(settings, cloudConfiguration, ldapConfig, stepCerts, keycloak);
+        } else {
+            throw new UnsupportedOperationException("Unsupported cloud provider " + cloudProvider.getName());
+        }
+    }
+
+    private AzureCloudSettings azureCloudSettings(CloudSettings settings, CloudConfiguration cloudConfiguration,
+                                                  CloudConfiguration.LdapConfig ldapConfig,
+                                                  CloudConfiguration.StepCerts stepCerts,
+                                                  CloudConfiguration.Keycloak keycloak) {
+        return AzureCloudSettings.builder()
+                .azureRegion(cloudConfiguration.getRegion())
+                .azureResourceGroupName(cloudConfiguration.getAzureResourceGroupName())
+                .azureSecurityGroupName(cloudConfiguration.getSecurityGroupIds())
+                .ldapDn(ldapConfig.getDn())
+                .ldapHost(ldapConfig.getHost())
+                .ldapOu(ldapConfig.getOu())
+                .ldapUser(ldapConfig.getUser())
+                .ldapPassword(ldapConfig.getPassword())
+                .azureSubnetName(cloudConfiguration.getSubnetId())
+                .azureVpcName(cloudConfiguration.getVpcId())
+                .confKeyDir(cloudConfiguration.getConfKeyDir())
+                .azureIamUser(settings.getIamUser())
+                .sbn(cloudConfiguration.getServiceBaseName())
+                .os(cloudConfiguration.getOs())
+                .cloud(conf.getCloudProvider().getName())
+                .imageEnabled(String.valueOf(cloudConfiguration.isImageEnabled()))
+                .stepCertsEnabled(String.valueOf(stepCerts.isEnabled()))
+                .stepCertsRootCA(stepCerts.getRootCA())
+                .stepCertsKid(stepCerts.getKid())
+                .stepCertsKidPassword(stepCerts.getKidPassword())
+                .stepCertsCAURL(stepCerts.getCaURL())
+                .keycloakAuthServerUrl(keycloak.getAuthServerUrl())
+                .keycloakRealmName(keycloak.getRealmName())
+                .keycloakUser(keycloak.getUser())
+                .keycloakUserPassword(keycloak.getUserPassword())
+                .build();
+    }
+
+    private GcpCloudSettings gcpCloudSettings(CloudSettings settings, CloudConfiguration cloudConfiguration,
+                                              CloudConfiguration.LdapConfig ldapConfig,
+                                              CloudConfiguration.StepCerts stepCerts,
+                                              CloudConfiguration.Keycloak keycloak) {
+        return GcpCloudSettings.builder()
+                .projectId(cloudConfiguration.getGcpProjectId())
+                .vpcName(cloudConfiguration.getVpcId())
+                .subnetName(cloudConfiguration.getSubnetId())
+                .zone(cloudConfiguration.getZone())
+                .region(cloudConfiguration.getRegion())
+                .ldapDn(ldapConfig.getDn())
+                .ldapHost(ldapConfig.getHost())
+                .ldapOu(ldapConfig.getOu())
+                .ldapUser(ldapConfig.getUser())
+                .ldapPassword(ldapConfig.getPassword())
+                .sbn(cloudConfiguration.getServiceBaseName())
+                .cloud(conf.getCloudProvider().getName())
+                .os(cloudConfiguration.getOs())
+                .confKeyDir(cloudConfiguration.getConfKeyDir())
+                .gcpIamUser(settings.getIamUser())
+                .imageEnabled(String.valueOf(cloudConfiguration.isImageEnabled()))
+                .stepCertsEnabled(String.valueOf(stepCerts.isEnabled()))
+                .stepCertsRootCA(stepCerts.getRootCA())
+                .stepCertsKid(stepCerts.getKid())
+                .stepCertsKidPassword(stepCerts.getKidPassword())
+                .stepCertsCAURL(stepCerts.getCaURL())
+                .keycloakAuthServerUrl(keycloak.getAuthServerUrl())
+                .keycloakRealmName(keycloak.getRealmName())
+                .keycloakUser(keycloak.getUser())
+                .keycloakUserPassword(keycloak.getUserPassword())
+                .build();
+    }
+
+    private AwsCloudSettings awsCloudSettings(CloudSettings settings, CloudConfiguration cloudConfiguration,
+                                              CloudConfiguration.LdapConfig ldapConfig,
+                                              CloudConfiguration.StepCerts stepCerts,
+                                              CloudConfiguration.Keycloak keycloak) {
+        return AwsCloudSettings.builder()
+                .awsRegion(cloudConfiguration.getRegion())
+                .awsSecurityGroupIds(cloudConfiguration.getSecurityGroupIds())
+                .awsSubnetId(cloudConfiguration.getSubnetId())
+                .awsVpcId(cloudConfiguration.getVpcId())
+                .confTagResourceId(cloudConfiguration.getConfTagResourceId())
+                .awsNotebookSubnetId(cloudConfiguration.getNotebookSubnetId())
+                .awsNotebookVpcId(cloudConfiguration.getNotebookVpcId())
+                .awsIamUser(settings.getIamUser())
+                .zone(cloudConfiguration.getZone())
+                .ldapDn(ldapConfig.getDn())
+                .ldapHost(ldapConfig.getHost())
+                .ldapOu(ldapConfig.getOu())
+                .ldapUser(ldapConfig.getUser())
+                .ldapPassword(ldapConfig.getPassword())
+                .sbn(cloudConfiguration.getServiceBaseName())
+                .cloud(conf.getCloudProvider().getName())
+                .os(cloudConfiguration.getOs())
+                .confKeyDir(cloudConfiguration.getConfKeyDir())
+                .imageEnabled(String.valueOf(cloudConfiguration.isImageEnabled()))
+                .stepCertsEnabled(String.valueOf(stepCerts.isEnabled()))
+                .stepCertsRootCA(stepCerts.getRootCA())
+                .stepCertsKid(stepCerts.getKid())
+                .stepCertsKidPassword(stepCerts.getKidPassword())
+                .stepCertsCAURL(stepCerts.getCaURL())
+                .keycloakAuthServerUrl(keycloak.getAuthServerUrl())
+                .keycloakRealmName(keycloak.getRealmName())
+                .keycloakUser(keycloak.getUser())
+                .keycloakUserPassword(keycloak.getUserPassword())
+                .build();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutor.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutor.java
new file mode 100644
index 0000000..dee78ea
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutor.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+import com.epam.datalab.process.model.DatalabProcess;
+import com.epam.datalab.process.model.ProcessId;
+import com.epam.datalab.process.model.ProcessInfo;
+import com.google.inject.Singleton;
+
+@Singleton
+public class CommandExecutor implements ICommandExecutor {
+
+    public ProcessInfo executeSync(final String username, final String uuid, String command) throws Exception {
+        return DatalabProcess.getInstance().start(new ProcessId(username, uuid), "bash", "-c", command).get();
+
+    }
+
+    public void executeAsync(final String username, final String uuid, final String command) {
+        DatalabProcess.getInstance().start(new ProcessId(username, uuid), "bash", "-c", command);
+    }
+}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMock.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMock.java
new file mode 100644
index 0000000..33bd495
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMock.java
@@ -0,0 +1,114 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.process.builder.ProcessInfoBuilder;
+import com.epam.datalab.process.model.ProcessId;
+import com.epam.datalab.process.model.ProcessInfo;
+import com.google.common.collect.Lists;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+public class CommandExecutorMock implements ICommandExecutor {
+    private static final Logger LOGGER = LoggerFactory.getLogger(CommandExecutorMock.class);
+    public static final String DOCKER_DATALAB_DATAENGINE = "docker.datalab-dataengine:latest";
+    public static final String DOCKER_DATALAB_DATAENGINE_SERVICE = "docker.datalab-dataengine-service:latest";
+
+    private CommandExecutorMockAsync execAsync = null;
+    private CompletableFuture<Boolean> future;
+
+    private CloudProvider cloudProvider;
+
+    public CommandExecutorMock(CloudProvider cloudProvider) {
+        this.cloudProvider = cloudProvider;
+    }
+
+    /**
+     * Return result of execution.
+     *
+     * @throws ExecutionException
+     * @throws InterruptedException
+     */
+    public boolean getResultSync() throws InterruptedException, ExecutionException {
+        return (future == null ? true : future.get());
+    }
+
+    /**
+     * Return variables for substitution into Json response file.
+     */
+    public Map<String, String> getVariables() {
+        return (execAsync == null ? null : execAsync.getParser().getVariables());
+    }
+
+    /**
+     * Response file name.
+     */
+    public String getResponseFileName() {
+        return (execAsync == null ? null : execAsync.getResponseFileName());
+    }
+
+    @Override
+    public ProcessInfo executeSync(String user, String uuid, String command) {
+        LOGGER.debug("Run OS command for user {} with UUID {}: {}", user, uuid, command);
+        ProcessInfoBuilder builder = new ProcessInfoBuilder(new ProcessId(user, command), 1000l);
+        if (command.startsWith("docker images |")) {
+            List<String> list = Lists.newArrayList(
+                    "docker.datalab-deeplearning:latest",
+                    "docker.datalab-jupyter:latest",
+                    "docker.datalab-jupyterlab:latest",
+                    "docker.datalab-superset:latest",
+                    "docker.datalab-rstudio:latest",
+                    "docker.datalab-tensor:latest",
+                    "docker.datalab-zeppelin:latest",
+                    "docker.datalab-tensor-rstudio:latest");
+
+            list.addAll(getComputationalDockerImage());
+
+            ProcessInfoBuilder.stdOut(builder, String.join("\n", list));
+        }
+        return builder.get();
+    }
+
+    @Override
+    public void executeAsync(String user, String uuid, String command) {
+        execAsync = new CommandExecutorMockAsync(user, uuid, command, cloudProvider);
+        future = CompletableFuture.supplyAsync(execAsync);
+    }
+
+    private List<String> getComputationalDockerImage() {
+        switch (cloudProvider) {
+            case AWS:
+                return Lists.newArrayList(DOCKER_DATALAB_DATAENGINE_SERVICE, DOCKER_DATALAB_DATAENGINE);
+            case AZURE:
+                return Lists.newArrayList(DOCKER_DATALAB_DATAENGINE);
+            case GCP:
+                return Lists.newArrayList(DOCKER_DATALAB_DATAENGINE_SERVICE, DOCKER_DATALAB_DATAENGINE);
+            default:
+                throw new IllegalArgumentException("Unsupported cloud provider " + cloudProvider);
+        }
+    }
+
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMockAsync.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMockAsync.java
new file mode 100644
index 0000000..6d6c224
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMockAsync.java
@@ -0,0 +1,406 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.exploratory.LibInstallDTO;
+import com.epam.datalab.dto.exploratory.LibStatus;
+import com.epam.datalab.dto.status.EnvResource;
+import com.epam.datalab.dto.status.EnvResourceList;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.util.SecurityUtils;
+import com.epam.datalab.util.ServiceUtils;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Lists;
+import com.google.common.io.ByteStreams;
+import com.google.common.io.Files;
+import com.google.common.io.Resources;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.Charsets;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
+
+@Slf4j
+public class CommandExecutorMockAsync implements Supplier<Boolean> {
+    private static final String JSON_FILE_ENDING = ".json";
+
+    private static final ObjectMapper MAPPER = new ObjectMapper()
+            .configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true)
+            .setSerializationInclusion(JsonInclude.Include.NON_NULL);
+
+    private String user;
+    private String uuid;
+    private String command;
+
+    private CommandParserMock parser = new CommandParserMock();
+    private String responseFileName;
+
+    private CloudProvider cloudProvider;
+
+    public CommandExecutorMockAsync(String user, String uuid, String command, CloudProvider cloudProvider) {
+        this.user = user;
+        this.uuid = uuid;
+        this.command = command;
+        this.cloudProvider = cloudProvider;
+    }
+
+    @Override
+    public Boolean get() {
+        try {
+            run();
+        } catch (Exception e) {
+            log.error("Command with UUID {} fails: {}", uuid, e.getLocalizedMessage(), e);
+            return false;
+        }
+        return true;
+    }
+
+
+    /**
+     * Return parser of command line.
+     */
+    public CommandParserMock getParser() {
+        return parser;
+    }
+
+    /**
+     * Return variables for substitution into Json response file.
+     */
+    public Map<String, String> getVariables() {
+        return parser.getVariables();
+    }
+
+    /**
+     * Response file name.
+     */
+    public String getResponseFileName() {
+        return responseFileName;
+    }
+
+    public void run() {
+        log.debug("Run OS command for user {} with UUID {}: {}", user, uuid, SecurityUtils.hideCreds(command));
+
+        responseFileName = null;
+        parser = new CommandParserMock(command, uuid);
+        log.debug("Parser is {}", SecurityUtils.hideCreds(parser.toString()));
+        DockerAction action = DockerAction.of(parser.getAction());
+        log.debug("Action is {}", action);
+
+        if (parser.isDockerCommand()) {
+            if (action == null) {
+                throw new DatalabException("Docker action not defined");
+            }
+
+            sleep(500);
+
+            try {
+                switch (action) {
+                    case DESCRIBE:
+                        describe();
+                        break;
+                    case CREATE:
+                    case START:
+                    case STOP:
+                    case TERMINATE:
+                    case GIT_CREDS:
+                    case CREATE_IMAGE:
+                    case RECONFIGURE_SPARK:
+                    case CHECK_INACTIVITY:
+                        action(user, action);
+                        break;
+                    case CONFIGURE:
+                    case REUPLOAD_KEY:
+                        sleep(1000);
+                        action(user, action);
+                        break;
+                    case STATUS:
+                        parser.getVariables().put("list_resources", getResponseStatus(true));
+                        action(user, action);
+                        break;
+                    case LIB_LIST:
+                        action(user, action);
+                        copyFile(String.format("mock_response/%s/notebook_lib_list_pkgs.json",
+                                cloudProvider.getName()),
+                                String.join("_", "notebook", uuid, "all_pkgs") +
+                                        JSON_FILE_ENDING, parser.getResponsePath());
+                        break;
+                    case LIB_INSTALL:
+                        parser.getVariables().put("lib_install", getResponseLibInstall(true));
+                        action(user, action);
+                        break;
+                    default:
+                        break;
+                }
+            } catch (Exception e) {
+                String msg = "Cannot execute command for user " + user + " with UUID " + uuid + ". " +
+                        e.getLocalizedMessage();
+                log.error(msg, e);
+                throw new DatalabException(msg, e);
+            }
+        } else {
+            final String scriptName = StringUtils.substringBefore(Paths.get(parser.getCommand()).getFileName()
+                    .toString(), ".");
+            String templateFileName = "mock_response/" + cloudProvider.getName() + '/' + scriptName + JSON_FILE_ENDING;
+            responseFileName = getAbsolutePath(parser.getResponsePath(), scriptName + user + "_" +
+                    parser.getRequestId() + JSON_FILE_ENDING);
+            setResponse(templateFileName, responseFileName);
+        }
+
+    }
+
+    private void sleep(int ms) {
+        try {
+            Thread.sleep(ms);
+        } catch (InterruptedException e) {
+            log.error("InterruptedException occurred: {}", e.getMessage());
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    private static void copyFile(String sourceFilePath, String destinationFileName, String destinationFolder) throws
+            IOException {
+        File to = new File(getAbsolutePath(destinationFolder, destinationFileName));
+
+        try (InputStream inputStream =
+                     CommandExecutorMockAsync.class.getClassLoader().getResourceAsStream(sourceFilePath);
+             OutputStream outputStream = new FileOutputStream(to)) {
+            ByteStreams.copy(inputStream, outputStream);
+        }
+
+        log.debug("File {} copied to {}", sourceFilePath, to);
+    }
+
+    /**
+     * Return absolute path to the file or folder.
+     *
+     * @param first part of path.
+     * @param more  next path components.
+     */
+    private static String getAbsolutePath(String first, String... more) {
+        return Paths.get(first, more).toAbsolutePath().toString();
+    }
+
+    /**
+     * Tests the directory exists.
+     *
+     * @param dir the name of directory.
+     * @return <b>true</b> if the directory exists otherwise return <b>false</b>.
+     */
+    private boolean dirExists(String dir) {
+        File file = new File(dir);
+        return (file.exists() && file.isDirectory());
+    }
+
+    /**
+     * Find and return the directory "infrastructure-provisioning/src".
+     *
+     * @throws FileNotFoundException may be thrown
+     */
+    private String findTemplatesDir() throws FileNotFoundException {
+        String dir = System.getProperty("docker.dir");
+
+        if (dir != null) {
+            dir = getAbsolutePath(dir);
+            if (dirExists(dir)) {
+                return dir;
+            }
+            throw new FileNotFoundException("Directory \"" + dir + "\" not found. " +
+                    "Please set JVM argument -Ddocker.dir to the " +
+                    "\".../infrastructure-provisioning/src/general/files/" + cloudProvider.getName() + "\" directory");
+        }
+        dir = getAbsolutePath(
+                ".",
+                "../../infrastructure-provisioning/src/general/files/" + cloudProvider.getName());
+        if (dirExists(dir)) {
+            return dir;
+        }
+        dir = getAbsolutePath(
+                ServiceUtils.getUserDir(),
+                "../../infrastructure-provisioning/src/general/files/" + cloudProvider.getName());
+        if (dirExists(dir)) {
+            return dir;
+        }
+        throw new FileNotFoundException("Directory \"" + dir + "\" not found. " +
+                "Please set the value docker.dir property to the " +
+                "\".../infrastructure-provisioning/src/general/files/" + cloudProvider.getName() + "\" directory");
+    }
+
+    /**
+     * Describe action.
+     */
+    private void describe() {
+        String templateFileName;
+        try {
+            templateFileName = getAbsolutePath(findTemplatesDir(), parser.getImageType() + "_description.json");
+        } catch (FileNotFoundException e) {
+            throw new DatalabException("Cannot describe image " + parser.getImageType() + ". " + e.getLocalizedMessage(),
+                    e);
+        }
+        responseFileName = getAbsolutePath(parser.getResponsePath(), parser.getRequestId() + JSON_FILE_ENDING);
+
+        log.debug("Create response file from {} to {}", templateFileName, responseFileName);
+        File fileResponse = new File(responseFileName);
+        File fileTemplate = new File(templateFileName);
+        try {
+            if (!fileTemplate.exists()) {
+                throw new FileNotFoundException("File \"" + fileTemplate + "\" not found.");
+            }
+            if (!fileTemplate.canRead()) {
+                throw new IOException("Cannot read file \"" + fileTemplate + "\".");
+            }
+            Files.createParentDirs(fileResponse);
+            Files.copy(fileTemplate, fileResponse);
+        } catch (IOException e) {
+            throw new DatalabException("Can't create response file " + responseFileName + ": " + e.getLocalizedMessage(),
+                    e);
+        }
+    }
+
+    /**
+     * Perform docker action.
+     *
+     * @param user   the name of user.
+     * @param action docker action.
+     */
+    private void action(String user, DockerAction action) {
+        String resourceType = parser.getResourceType();
+
+        String prefixFileName = (Lists.newArrayList("project", "edge", "dataengine", "dataengine-service")
+                .contains(resourceType) ? resourceType : "notebook") + "_";
+        String templateFileName = "mock_response/" + cloudProvider.getName() + '/' + prefixFileName +
+                action.toString() + JSON_FILE_ENDING;
+        responseFileName = getAbsolutePath(parser.getResponsePath(), prefixFileName + user + "_" +
+                parser.getRequestId() + JSON_FILE_ENDING);
+        setResponse(templateFileName, responseFileName);
+    }
+
+    /**
+     * Return the section of resource statuses for docker action status.
+     */
+    private String getResponseStatus(boolean noUpdate) {
+        if (noUpdate) {
+            return "{}";
+        }
+        EnvResourceList resourceList;
+        try {
+            JsonNode json = MAPPER.readTree(parser.getJson());
+            json = json.get("edge_list_resources");
+            resourceList = MAPPER.readValue(json.toString(), EnvResourceList.class);
+        } catch (IOException e) {
+            throw new DatalabException("Can't parse json content: " + e.getLocalizedMessage(), e);
+        }
+
+        if (resourceList.getHostList() != null) {
+            for (EnvResource host : resourceList.getHostList()) {
+                host.setStatus(UserInstanceStatus.RUNNING.toString());
+            }
+        }
+        if (resourceList.getClusterList() != null) {
+            for (EnvResource host : resourceList.getClusterList()) {
+                host.setStatus(UserInstanceStatus.RUNNING.toString());
+            }
+        }
+
+        try {
+            return MAPPER.writeValueAsString(resourceList);
+        } catch (JsonProcessingException e) {
+            throw new DatalabException("Can't generate json content: " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Return the section of resource statuses for docker action status.
+     */
+    private String getResponseLibInstall(boolean isSuccess) {
+        List<LibInstallDTO> list;
+        try {
+            JsonNode json = MAPPER.readTree(parser.getJson());
+            json = json.get("libs");
+            list = MAPPER.readValue(json.toString(), new TypeReference<List<LibInstallDTO>>() {
+            });
+        } catch (IOException e) {
+            throw new DatalabException("Can't parse json content: " + e.getLocalizedMessage(), e);
+        }
+
+        for (LibInstallDTO lib : list) {
+            if (isSuccess) {
+                lib.setStatus(LibStatus.INSTALLED.toString());
+            } else {
+                lib.setStatus(LibStatus.INSTALLATION_ERROR.toString());
+                lib.setErrorMessage("Mock error message");
+            }
+        }
+
+        try {
+            return MAPPER.writeValueAsString(list);
+        } catch (JsonProcessingException e) {
+            throw new DatalabException("Can't generate json content: " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Write response file.
+     *
+     * @param sourceFileName template file name.
+     * @param targetFileName response file name.
+     */
+    private void setResponse(String sourceFileName, String targetFileName) {
+        String content;
+        URL url = Resources.getResource(sourceFileName);
+        try {
+            content = Resources.toString(url, Charsets.UTF_8);
+        } catch (IOException e) {
+            throw new DatalabException("Can't read resource " + sourceFileName + ": " + e.getLocalizedMessage(), e);
+        }
+
+        for (String key : parser.getVariables().keySet()) {
+            String value = parser.getVariables().get(key);
+            content = content.replace("${" + key.toUpperCase() + "}", value);
+        }
+
+        File fileResponse = new File(responseFileName);
+        try (BufferedWriter out = new BufferedWriter(new FileWriter(fileResponse))) {
+            Files.createParentDirs(fileResponse);
+            out.write(content);
+        } catch (IOException e) {
+            throw new DatalabException("Can't write response file " + targetFileName + ": " + e.getLocalizedMessage(), e);
+        }
+        log.debug("Create response file from {} to {}", sourceFileName, targetFileName);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandParserMock.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandParserMock.java
new file mode 100644
index 0000000..c454fcd
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandParserMock.java
@@ -0,0 +1,377 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+import com.epam.datalab.exceptions.DatalabException;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.MoreObjects;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Parse command for emulate commands of Docker.
+ */
+public class CommandParserMock {
+    private ObjectMapper MAPPER = new ObjectMapper()
+            .configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true)
+            .setSerializationInclusion(JsonInclude.Include.NON_NULL);
+
+    private String command;
+    private String action;
+    private String resourceType;
+    private String imageType;
+    private String requestId;
+    private String responsePath;
+    private String name;
+    private String json;
+    private Map<String, String> envMap = new HashMap<>();
+    private Map<String, String> varMap = new HashMap<>();
+    private List<String> otherArgs = new ArrayList<>();
+    private Map<String, String> variables = new HashMap<>();
+    private boolean dockerCommand;
+
+    public CommandParserMock() {
+    }
+
+    public CommandParserMock(String command, String uuid) {
+        parse(command, uuid);
+    }
+
+
+    /**
+     * Return the name of docker command.
+     */
+    public String getCommand() {
+        return command;
+    }
+
+    /**
+     * Return the name of docker action.
+     */
+    public String getAction() {
+        return action;
+    }
+
+    /**
+     * Return the type of resource.
+     */
+    public String getResourceType() {
+        return resourceType;
+    }
+
+    /**
+     * Return the image type.
+     */
+    public String getImageType() {
+        return imageType;
+    }
+
+    /**
+     * Return the request id.
+     */
+    public String getRequestId() {
+        return requestId;
+    }
+
+    /**
+     * Return the path for response files.
+     */
+    public String getResponsePath() {
+        return responsePath;
+    }
+
+    /**
+     * Return name of docker container.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Return content of Json if present otherwise <b>null</b>.
+     */
+    public String getJson() {
+        return json;
+    }
+
+    /**
+     * Return map of environment variables.
+     */
+    public Map<String, String> getVariables() {
+        return variables;
+    }
+
+    /**
+     * Add argument to list.
+     *
+     * @param args list of arguments.
+     * @param arg  argument.
+     */
+    private void addArgToList(List<String> args, String arg) {
+        if (arg == null) {
+            return;
+        }
+        if (arg.length() > 1) {
+            if (arg.startsWith("'") && arg.endsWith("'")) {
+                arg = arg.substring(1, arg.length() - 1);
+            }
+            if (arg.startsWith("\"") && arg.endsWith("\"")) {
+                arg = arg.substring(1, arg.length() - 1);
+            }
+        }
+        arg = arg.trim();
+        if (arg.isEmpty()) {
+            return;
+        }
+
+        args.add(arg);
+    }
+
+    /**
+     * Extract arguments from command line.
+     *
+     * @param cmd command line.
+     * @return List of arguments.
+     */
+    private List<String> extractArgs(String cmd) {
+        boolean isQuote = false;
+        boolean isDoubleQuote = false;
+        List<String> args = new ArrayList<>();
+        int pos = 0;
+
+        for (int i = 0; i < cmd.length(); i++) {
+            final char c = cmd.charAt(i);
+            if (c == '\'') {
+                isQuote = !isQuote;
+                continue;
+            }
+            if (c == '"') {
+                isDoubleQuote = !isDoubleQuote;
+                continue;
+            }
+
+            if (!isQuote && !isDoubleQuote && c == ' ') {
+                addArgToList(args, cmd.substring(pos, i));
+                pos = i + 1;
+            }
+        }
+        if (!isQuote && !isDoubleQuote) {
+            addArgToList(args, cmd.substring(pos));
+        }
+
+        return args;
+    }
+
+    /**
+     * Return the value of argument.
+     *
+     * @param args    list of arguments.
+     * @param index   index of named arguments
+     * @param argName name of argument.
+     */
+    private String getArgValue(List<String> args, int index, String argName) {
+        if (!args.get(index).equals(argName)) {
+            return null;
+        }
+        args.remove(index);
+        if (index < args.size()) {
+            String value = args.get(index);
+            args.remove(index);
+            return value;
+        }
+        throw new DatalabException("Argument \"" + argName + "\" detected but not have value");
+    }
+
+    /**
+     * Return pair name/value separated.
+     *
+     * @param argName   name of argument.
+     * @param value     value.
+     * @param separator separator.
+     */
+    private Pair<String, String> getPair(String argName, String value, String separator) {
+        String[] array = value.split(separator);
+        if (array.length != 2) {
+            throw new DatalabException("Invalid value for \"" + argName + "\": " + value);
+        }
+        return new ImmutablePair<>(array[0], array[1]);
+    }
+
+    /**
+     * Return name of docker image.
+     *
+     * @param args list of arguments.
+     * @throws if image name not found.
+     */
+    public static String getImageName(List<String> args) {
+        for (String s : args) {
+            if (s.startsWith("docker.datalab-")) {
+                return s;
+            }
+        }
+        throw new DatalabException("Name of docker image not found");
+    }
+
+    /**
+     * Extract Json properties from Json content.
+     *
+     * @param jsonContent Json content.
+     * @return
+     */
+    private Map<String, String> getJsonVariables(String jsonContent) {
+        Map<String, String> vars = new HashMap<>();
+        if (jsonContent == null) {
+            return vars;
+        }
+
+        JsonNode json;
+        try {
+            json = MAPPER.readTree(jsonContent);
+        } catch (IOException e) {
+            throw new DatalabException("Can't parse json content: " + e.getLocalizedMessage(), e);
+        }
+
+        Iterator<String> keys = json.fieldNames();
+        while (keys.hasNext()) {
+            String key = keys.next();
+            String value = getTextValue(json.get(key));
+            if (value != null) {
+                vars.put(key, value);
+            }
+        }
+        return vars;
+    }
+
+    /**
+     * Return the value of json property or <b>null</b>.
+     *
+     * @param jsonNode - Json node.
+     */
+    private String getTextValue(JsonNode jsonNode) {
+        return jsonNode != null ? jsonNode.textValue() : null;
+    }
+
+    /**
+     * Parse command line.
+     *
+     * @param cmd command line.
+     */
+    public void parse(String cmd, String uuid) {
+        command = null;
+        action = null;
+        resourceType = null;
+        imageType = null;
+        requestId = uuid;
+        responsePath = null;
+        name = null;
+        json = null;
+
+        envMap.clear();
+        varMap.clear();
+        otherArgs.clear();
+        variables.clear();
+
+        List<String> args = extractArgs(cmd);
+        dockerCommand = args.contains("docker");
+        int i = 0;
+        String s;
+        Pair<String, String> p;
+
+        while (i < args.size()) {
+            if ((s = getArgValue(args, i, "-v")) != null) {
+                p = getPair("-v", s, ":");
+                varMap.put(p.getValue(), p.getKey());
+            } else if ((s = getArgValue(args, i, "-e")) != null) {
+                p = getPair("-e", s, "=");
+                envMap.put(p.getKey(), p.getValue());
+            } else if ((s = getArgValue(args, i, "docker")) != null || (s = getArgValue(args, i, "python")) != null) {
+                command = s;
+            } else if ((s = getArgValue(args, i, "--action")) != null) {
+                action = s;
+            } else if ((s = getArgValue(args, i, "--name")) != null) {
+                name = s;
+            } else if ((s = getArgValue(args, i, "echo")) != null) {
+                if (s.equals("-e")) {
+                    if (i >= args.size()) {
+                        throw new DatalabException("Argument \"echo -e\" detected but not have value");
+                    }
+                    s = args.get(i);
+                    args.remove(i);
+                }
+                json = s;
+            } else if ((s = getArgValue(args, i, "--result_path")) != null) {
+                responsePath = s;
+                varMap.put("/response", responsePath);
+                args.remove(i);
+            } else {
+                i++;
+            }
+        }
+
+        if (args.size() > 0) {
+            otherArgs.addAll(args);
+        }
+
+        resourceType = envMap.get("conf_resource");
+        if (isDockerCommand()) {
+            imageType = getImageName(args);
+            imageType = imageType.replace("docker.datalab-", "").replace(":latest", "");
+        }
+        responsePath = varMap.get("/response");
+
+        variables.putAll(envMap);
+        variables.putAll(getJsonVariables(json));
+        variables.put("request_id", requestId);
+        variables.put("instance_id", "i-" + requestId.replace("-", "").substring(0, 17));
+        variables.put("cluster_id", "j-" + requestId.replace("-", "").substring(0, 13).toUpperCase());
+        variables.put("notebook_id", requestId.replace("-", "").substring(17, 22));
+    }
+
+    public boolean isDockerCommand() {
+        return dockerCommand;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("command", command)
+                .add("action", action)
+                .add("resourceType", resourceType)
+                .add("imageType", imageType)
+                .add("requestId", requestId)
+                .add("responsePath", responsePath)
+                .add("name", name)
+                .add("environment", envMap)
+                .add("variable", varMap)
+                .add("others", otherArgs)
+                .add("json", json)
+                .toString();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerAction.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerAction.java
new file mode 100644
index 0000000..f06c94d
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerAction.java
@@ -0,0 +1,54 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+public enum DockerAction {
+    DESCRIBE,
+    CREATE,
+    START,
+    CONFIGURE,
+    RUN,
+    STOP,
+    TERMINATE,
+    LIB_LIST,
+    LIB_INSTALL,
+    GIT_CREDS,
+    CREATE_IMAGE,
+    STATUS,
+    REUPLOAD_KEY,
+    RECONFIGURE_SPARK,
+    CHECK_INACTIVITY;
+
+    public static DockerAction of(String action) {
+        if (action != null) {
+            for (DockerAction uis : DockerAction.values()) {
+                if (action.equalsIgnoreCase(uis.toString())) {
+                    return uis;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString().toLowerCase();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerCommands.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerCommands.java
new file mode 100644
index 0000000..e8f03d1
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerCommands.java
@@ -0,0 +1,69 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.UUID;
+
+@FunctionalInterface
+public interface DockerCommands {
+    String GET_IMAGES = new ImagesDockerCommand()
+            .pipe(UnixCommand.awk("{print $1\":\"$2}"))
+            .pipe(UnixCommand.sort())
+            .pipe(UnixCommand.uniq())
+            .pipe(UnixCommand.grep("datalab"))
+            .pipe(UnixCommand.grep("none", "-v"))
+            .pipe(UnixCommand.grep("base", "-v"))
+            .pipe(UnixCommand.grep("ssn", "-v"))
+            .pipe(UnixCommand.grep("edge", "-v"))
+            .pipe(UnixCommand.grep("project", "-v"))
+            .toCMD();
+
+    String GET_RUNNING_CONTAINERS_FOR_USER = "docker ps --format \"{{.Names}}\" -f name=%s";
+
+    ObjectMapper MAPPER = new ObjectMapper()
+            .configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
+
+    static String generateUUID() {
+        return UUID.randomUUID().toString();
+    }
+
+    static String extractUUID(String fileName) {
+        Integer beginIndex = fileName.lastIndexOf('_');
+        Integer endIndex = fileName.lastIndexOf('.');
+        beginIndex = beginIndex < 0 ? 0 : beginIndex + 1;
+        if (endIndex < 0) {
+            endIndex = fileName.length();
+        }
+        if (beginIndex > endIndex) {
+            beginIndex = endIndex;
+        }
+        return fileName.substring(beginIndex, endIndex);
+    }
+
+    default String nameContainer(String... names) {
+        return String.join("_", names) + "_" + System.currentTimeMillis();
+    }
+
+    String getResourceType();
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/ICommandExecutor.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/ICommandExecutor.java
new file mode 100644
index 0000000..da1082e
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/ICommandExecutor.java
@@ -0,0 +1,27 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+import com.epam.datalab.process.model.ProcessInfo;
+
+public interface ICommandExecutor {
+    ProcessInfo executeSync(String username, String uuid, String command) throws Exception;
+
+    void executeAsync(String username, String uuid, String command);
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/ImagesDockerCommand.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/ImagesDockerCommand.java
new file mode 100644
index 0000000..773f206
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/ImagesDockerCommand.java
@@ -0,0 +1,53 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class ImagesDockerCommand implements CmdCommand {
+    private String command = "docker images";
+
+    private List<UnixCommand> unixCommands;
+
+    public ImagesDockerCommand pipe(UnixCommand unixCommand) {
+        if (unixCommands == null) {
+            unixCommands = new LinkedList<>();
+        }
+        unixCommands.add(unixCommand);
+        return this;
+    }
+
+    @Override
+    public String toCMD() {
+        StringBuilder sb = new StringBuilder(command);
+        if (unixCommands != null) {
+            for (UnixCommand unixCommand : unixCommands) {
+                sb.append(" | ").append(unixCommand.getCommand());
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public String toString() {
+        return toCMD();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/PythonBackupCommand.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/PythonBackupCommand.java
new file mode 100644
index 0000000..8f1f8ab
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/PythonBackupCommand.java
@@ -0,0 +1,81 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+import java.util.List;
+
+public class PythonBackupCommand extends PythonCommand {
+
+    private static final String ARG_DELIMITER = ",";
+    private static final String USER_NAME_SYSTEM_PROPERTY = "user.name";
+
+    public PythonBackupCommand(String fileName) {
+        super(fileName);
+    }
+
+    public PythonBackupCommand withConfig(List<String> configs) {
+        withOption("--config", String.join(ARG_DELIMITER, configs));
+        return this;
+    }
+
+    public PythonBackupCommand withKeys(List<String> keys) {
+        withOption("--keys", String.join(ARG_DELIMITER, keys));
+        return this;
+    }
+
+    public PythonBackupCommand withJars(List<String> jars) {
+        withOption("--jars", String.join(ARG_DELIMITER, jars));
+        return this;
+    }
+
+    public PythonBackupCommand withDBBackup(boolean dbBackup) {
+        if (dbBackup) {
+            withOption("--db");
+        }
+        return this;
+    }
+
+    public PythonBackupCommand withCertificates(List<String> certificates) {
+        withOption("--certs", String.join(ARG_DELIMITER, certificates));
+        return this;
+    }
+
+    public PythonBackupCommand withSystemUser() {
+        withOption("--user", System.getProperty(USER_NAME_SYSTEM_PROPERTY));
+        return this;
+    }
+
+    public PythonBackupCommand withLogsBackup(boolean logsBackup) {
+        if (logsBackup) {
+            withOption("--logs");
+        }
+        return this;
+    }
+
+    public PythonBackupCommand withRequestId(String requestId) {
+        withOption("--request_id", requestId);
+        return this;
+    }
+
+    public PythonBackupCommand withResponsePath(String responsePath) {
+        withOption("--result_path", responsePath);
+        return this;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/PythonCommand.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/PythonCommand.java
new file mode 100644
index 0000000..d6a302d
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/PythonCommand.java
@@ -0,0 +1,50 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PythonCommand implements CmdCommand {
+    private static final String PYTHON = "python ";
+    private final String fileName;
+    private List<String> options = new ArrayList<>();
+
+    public PythonCommand(String fileName) {
+        this.fileName = fileName;
+    }
+
+    public PythonCommand withOption(String option) {
+        options.add(option);
+        return this;
+    }
+
+    public PythonCommand withOption(String key, String value) {
+        options.add(key + " " + value);
+        return this;
+    }
+
+    @Override
+    public String toCMD() {
+        return PYTHON + fileName + StringUtils.SPACE + String.join(StringUtils.SPACE, options);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/RunDockerCommand.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/RunDockerCommand.java
new file mode 100644
index 0000000..66ca1be
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/RunDockerCommand.java
@@ -0,0 +1,285 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+import java.nio.file.Paths;
+import java.util.LinkedList;
+import java.util.List;
+
+public class RunDockerCommand implements CmdCommand {
+    public static final String EDGE_USER_NAME_FORMAT = "-e \"edge_user_name=%s\"";
+    private String command = "docker run";
+    private List<String> options = new LinkedList<>();
+    private String image;
+    private DockerAction action;
+
+    private static final String ROOT_KEYS_PATH = "/root/keys";
+    private static final String RESPONSE_PATH = "/response";
+    private static final String LOG_PATH = "/logs";
+    private static final String AZURE_AUTH_FILE = "/root/azure_auth.json";
+
+    public RunDockerCommand withVolume(String hostSrcPath, String bindPath) {
+        options.add(String.format("-v %s:%s", hostSrcPath, bindPath));
+        return this;
+    }
+
+    public RunDockerCommand withVolumeForRootKeys(String hostSrcPath) {
+        return withVolume(hostSrcPath, ROOT_KEYS_PATH);
+    }
+
+    public RunDockerCommand withVolumeForResponse(String hostSrcPath) {
+        return withVolume(hostSrcPath, RESPONSE_PATH);
+    }
+
+    public RunDockerCommand withVolumeFoAzureAuthFile(String hostSrcPath) {
+        return withVolume(hostSrcPath, AZURE_AUTH_FILE);
+    }
+
+    public RunDockerCommand withVolumeForLog(String hostSrcPath, String logDirectory) {
+        return withVolume(Paths.get(hostSrcPath, logDirectory).toString(),
+                Paths.get(LOG_PATH, logDirectory).toString());
+    }
+
+    public RunDockerCommand withName(String name) {
+        options.add(String.format("--name %s", name));
+        return this;
+    }
+
+    public RunDockerCommand withRequestId(String requestId) {
+        options.add(String.format("-e \"request_id=%s\"", requestId));
+        return this;
+    }
+
+    public RunDockerCommand withAtach(String value) {
+        options.add(String.format("-a %s", value));
+        return this;
+    }
+
+    public RunDockerCommand withInteractive() {
+        options.add("-i");
+        return this;
+    }
+
+    public RunDockerCommand withDetached() {
+        options.add("-d");
+        return this;
+    }
+
+    public RunDockerCommand withPseudoTTY() {
+        options.add("-t");
+        return this;
+    }
+
+    public RunDockerCommand withImage(String image) {
+        this.image = image;
+        return this;
+    }
+
+    public RunDockerCommand withAction(DockerAction action) {
+        this.action = action;
+        return this;
+    }
+
+    public RunDockerCommand withActionDescribe(String toDescribe) {
+        this.image = toDescribe;
+        this.action = DockerAction.DESCRIBE;
+        return this;
+    }
+
+    public RunDockerCommand withActionCreate(String toCreate) {
+        this.image = toCreate;
+        this.action = DockerAction.CREATE;
+        return this;
+    }
+
+    public RunDockerCommand withActionConfigure(String toConfigue) {
+        this.image = toConfigue;
+        this.action = DockerAction.CONFIGURE;
+        return this;
+    }
+
+    public RunDockerCommand withActionStatus(String toStatus) {
+        this.image = toStatus;
+        this.action = DockerAction.STATUS;
+        return this;
+    }
+
+    public RunDockerCommand withActionStart(String toStart) {
+        this.image = toStart;
+        this.action = DockerAction.START;
+        return this;
+    }
+
+    public RunDockerCommand withActionRun(String toRun) {
+        this.image = toRun;
+        this.action = DockerAction.RUN;
+        return this;
+    }
+
+    public RunDockerCommand withActionTerminate(String toTerminate) {
+        this.image = toTerminate;
+        this.action = DockerAction.TERMINATE;
+        return this;
+    }
+
+    public RunDockerCommand withActionStop(String toStop) {
+        this.image = toStop;
+        this.action = DockerAction.STOP;
+        return this;
+    }
+
+    public RunDockerCommand withConfKeyName(String confKeyName) {
+        options.add(String.format("-e \"conf_key_name=%s\"", confKeyName));
+        return this;
+    }
+
+    public RunDockerCommand withConfServiceBaseName(String confServiceBaseName) {
+        options.add(String.format("-e \"conf_service_base_name=%s\"", confServiceBaseName));
+        return this;
+    }
+
+    public RunDockerCommand withConfOsFamily(String confOsFamily) {
+        options.add(String.format("-e \"conf_os_family=%s\"", confOsFamily));
+        return this;
+    }
+
+    public RunDockerCommand withEmrInstanceCount(String emrInstanceCount) {
+        options.add(String.format("-e \"emr_instance_count=%s\"", emrInstanceCount));
+        return this;
+    }
+
+    public RunDockerCommand withAwsVpcId(String awsVpcId) {
+        options.add(String.format("-e \"aws_vpc_id=%s\"", awsVpcId));
+        return this;
+    }
+
+    public RunDockerCommand withAwsSubnetId(String awsSubnetId) {
+        options.add(String.format("-e \"aws_subnet_id=%s\"", awsSubnetId));
+        return this;
+    }
+
+    public RunDockerCommand withEmrInstanceType(String emrInstanceType) {
+        options.add(String.format("-e \"emr_instance_type=%s\"", emrInstanceType));
+        return this;
+    }
+
+    public RunDockerCommand withEmrVersion(String emrVersion) {
+        options.add(String.format("-e \"emr_version=%s\"", emrVersion));
+        return this;
+    }
+
+    public RunDockerCommand withEmrTimeout(String emrTimeout) {
+        options.add(String.format("-e \"emr_timeout=%s\"", emrTimeout));
+        return this;
+    }
+
+    public RunDockerCommand withEc2Role(String ec2Role) {
+        options.add(String.format("-e \"ec2_role=%s\"", ec2Role));
+        return this;
+    }
+
+    public RunDockerCommand withServiceRole(String serviceRole) {
+        options.add(String.format("-e \"service_role=%s\"", serviceRole));
+        return this;
+    }
+
+    public RunDockerCommand withNotebookName(String notebookName) {
+        options.add(String.format("-e \"notebook_name=%s\"", notebookName));
+        return this;
+    }
+
+    public RunDockerCommand withEdgeSubnetCidr(String edgeSubnetCidr) {
+        options.add(String.format("-e \"edge_subnet_cidr=%s\"", edgeSubnetCidr));
+        return this;
+    }
+
+    public RunDockerCommand withAwsRegion(String awsRegion) {
+        options.add(String.format("-e \"aws_region=%s\"", awsRegion));
+        return this;
+    }
+
+    public RunDockerCommand withEdgeUserName(String edgeUserName) {
+        options.add(String.format(EDGE_USER_NAME_FORMAT, edgeUserName));
+        return this;
+    }
+
+    public RunDockerCommand withEmrClusterName(String emrClusterName) {
+        options.add(String.format("-e \"emr_cluster_name=%s\"", emrClusterName));
+        return this;
+    }
+
+    public RunDockerCommand withNotebookUserName(String notebookUserName) {
+        options.add(String.format(EDGE_USER_NAME_FORMAT, notebookUserName));
+        return this;
+    }
+
+    public RunDockerCommand withNotebookSubnetCidr(String notebookSubnetCidr) {
+        options.add(String.format("-e \"notebook_subnet_cidr=%s\"", notebookSubnetCidr));
+        return this;
+    }
+
+    public RunDockerCommand withAwsSecurityGroupsIds(String awsSecurityGroupsIds) {
+        options.add(String.format("-e \"aws_security_groups_ids=%s\"", awsSecurityGroupsIds));
+        return this;
+    }
+
+    public RunDockerCommand withNotebookInstanceName(String notebookInstanceName) {
+        options.add(String.format("-e \"notebook_instance_name=%s\"", notebookInstanceName));
+        return this;
+    }
+
+    public RunDockerCommand withUserKeyName(String userKeyName) {
+        options.add(String.format(EDGE_USER_NAME_FORMAT, userKeyName));
+        return this;
+    }
+
+    public RunDockerCommand withDryRun() {
+        options.add("-e \"dry_run=true\"");
+        return this;
+    }
+
+    public RunDockerCommand withResource(String resourceType) {
+        options.add(String.format("-e \"conf_resource=%s\"", resourceType));
+        return this;
+    }
+
+    public RunDockerCommand withRemove() {
+        options.add("--rm");
+        return this;
+    }
+
+    @Override
+    public String toCMD() {
+        StringBuilder sb = new StringBuilder(command);
+        for (String option : options) {
+            sb.append(" ").append(option);
+        }
+        if (image != null && action != null) {
+            sb.append(" ").append(image).append(" --action ").append(action.toString());
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public String toString() {
+        return toCMD();
+    }
+
+}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/UnixCommand.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/UnixCommand.java
new file mode 100644
index 0000000..18165cb
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/UnixCommand.java
@@ -0,0 +1,53 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+public class UnixCommand {
+    private String command;
+
+    public UnixCommand(String command) {
+        this.command = command;
+    }
+
+    public static UnixCommand awk(String txt) {
+        return new UnixCommand("awk '" + txt + "'");
+    }
+
+    public static UnixCommand sort() {
+        return new UnixCommand("sort");
+    }
+
+    public static UnixCommand uniq() {
+        return new UnixCommand("uniq");
+    }
+
+    public static UnixCommand grep(String searchFor, String... options) {
+        StringBuilder sb = new StringBuilder("grep");
+        for (String option : options) {
+            sb.append(' ').append(option);
+        }
+        sb.append(" \"" + searchFor + "\"");
+        return new UnixCommand(sb.toString());
+    }
+
+    public String getCommand() {
+        return command;
+    }
+}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/AsyncFileHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/AsyncFileHandler.java
new file mode 100644
index 0000000..d29b451
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/AsyncFileHandler.java
@@ -0,0 +1,135 @@
+/*
+ * 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.datalab.backendapi.core.response.folderlistener;
+
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import io.dropwizard.util.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.function.Supplier;
+
+import static com.epam.datalab.backendapi.core.Constants.JSON_EXTENSION;
+import static com.epam.datalab.backendapi.core.Constants.LOG_EXTENSION;
+
+/* Handler for the file processing.
+ */
+public final class AsyncFileHandler implements Supplier<Boolean> {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(AsyncFileHandler.class);
+
+    /**
+     * File name.
+     */
+    private final String fileName;
+    /**
+     * Directory name.
+     */
+    private final String directory;
+    /**
+     * Implement of the file handler.
+     */
+    private final FileHandlerCallback fileHandlerCallback;
+    /**
+     * Timeout waiting for the file writing.
+     */
+    private final Duration fileLengthCheckDelay;
+
+    /**
+     * Create instance of the file handler.
+     *
+     * @param fileName             file name.
+     * @param directory            directory name.
+     * @param fileHandlerCallback  file handler for processing
+     * @param fileLengthCheckDelay timeout waiting for the file writing.
+     */
+    public AsyncFileHandler(String fileName, String directory, FileHandlerCallback fileHandlerCallback,
+                            Duration fileLengthCheckDelay) {
+        this.fileName = fileName;
+        this.directory = directory;
+        this.fileHandlerCallback = fileHandlerCallback;
+        this.fileLengthCheckDelay = fileLengthCheckDelay;
+    }
+
+    @Override
+    public Boolean get() {
+        Path path = Paths.get(directory, fileName);
+        try {
+            boolean result = fileHandlerCallback.handle(fileName, readBytes(path));
+            if (result) {
+                try {
+                    Files.deleteIfExists(path);
+                    Files.deleteIfExists(getLogFile());
+                    LOGGER.trace("Response {} and log files has been deleted", path.toAbsolutePath());
+                } catch (IOException e) {
+                    LOGGER.warn("Can't delete file {}", path.toAbsolutePath(), e);
+                }
+            }
+            return result;
+        } catch (Exception e) {
+            LOGGER.error("Could not handle file {} async", path.toAbsolutePath(), e);
+            fileHandlerCallback.handleError(e.getLocalizedMessage());
+        }
+        return false;
+    }
+
+    /**
+     * Returns the name of log file.
+     */
+    private Path getLogFile() {
+        return Paths.get(directory, fileName.replaceAll(JSON_EXTENSION, LOG_EXTENSION));
+    }
+
+    /**
+     * Returns the content of file.
+     *
+     * @param path source file.
+     * @return File content.
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    private byte[] readBytes(Path path) throws IOException, InterruptedException {
+        File file = path.toFile();
+        waitFileCompletelyWritten(file);
+        return Files.readAllBytes(path);
+    }
+
+    /**
+     * Waiting for the file writing. This method is blocking and return control when
+     * the file will no longer resize.
+     *
+     * @param file source file.
+     */
+    private void waitFileCompletelyWritten(File file) throws InterruptedException {
+        long before;
+        long after = file.length();
+        do {
+            before = after;
+            Thread.sleep(fileLengthCheckDelay.toMilliseconds());
+            after = file.length();
+        } while (before != after);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/FolderListener.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/FolderListener.java
new file mode 100644
index 0000000..f82f9cf
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/FolderListener.java
@@ -0,0 +1,434 @@
+/*
+ * 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.datalab.backendapi.core.response.folderlistener;
+
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.response.folderlistener.WatchItem.ItemStatus;
+import com.epam.datalab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
+import com.epam.datalab.exceptions.DatalabException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.epam.datalab.backendapi.core.Constants.JSON_EXTENSION;
+
+/**
+ * Listen the directories for the files creation and runs the file processing by {@link AsyncFileHandler}.
+ */
+public class FolderListener implements Runnable {
+    private static final Logger LOGGER = LoggerFactory.getLogger(FolderListener.class);
+    /**
+     * Timeout of the check the file creation in milliseconds.
+     */
+    public static final long LISTENER_TIMEOUT_MILLLIS = 1000;
+    /**
+     * Timeout of the idle for the folder listener in milliseconds.
+     */
+    public static final long LISTENER_IDLE_TIMEOUT_MILLLIS = 600L * 1000L;
+    /**
+     * Timeout of waiting for the directory creation in milliseconds.
+     */
+    private static final long WAIT_DIR_TIMEOUT_MILLIS = 500;
+
+    /**
+     * List of the folder listeners.
+     */
+    private static final List<FolderListener> listeners = new ArrayList<>();
+    /**
+     * Thread of the folder listener.
+     */
+    private Thread thread;
+    /**
+     * List of the file handles.
+     */
+    private WatchItemList itemList;
+    /**
+     * Flag of listening status.
+     */
+    private boolean isListen = false;
+    /**
+     * Time when expired of idle for folder listener in milliseconds.
+     */
+    private long expiredIdleMillis = 0;
+
+
+    private FolderListener() {
+    }
+
+    /**
+     * Creates thread of the folder listener
+     *
+     * @param directoryName Name of directory.
+     * @param dao
+     */
+    private FolderListener(String directoryName, CallbackHandlerDao dao) {
+        itemList = new WatchItemList(directoryName, dao);
+    }
+
+    /**
+     * Appends the file handler for processing to the folder listener and returns instance of the file handler.
+     *
+     * @param directoryName        Name of directory for listen.
+     * @param fileHandlerCallback  File handler for processing.
+     * @param timeoutMillis        Timeout waiting for the file creation in milliseconds.
+     * @param fileLengthCheckDelay Timeout waiting for the file writing in milliseconds.
+     * @param callbackHandlerDao   callbackHandlerDao for handlers
+     * @return Instance of the file handler.
+     */
+    public static WatchItem listen(String directoryName, FileHandlerCallback fileHandlerCallback,
+                                   long timeoutMillis, long fileLengthCheckDelay,
+                                   CallbackHandlerDao callbackHandlerDao) {
+        return listen(directoryName, fileHandlerCallback, timeoutMillis, fileLengthCheckDelay, null,
+                callbackHandlerDao);
+    }
+
+    /**
+     * Appends the file handler for processing to the folder listener for the existing file and returns
+     * instance of the file handler. If the file name is <b>null</b> this means that file does not exist
+     * and equal to call method
+     * {@link FolderListener#listen(String, FileHandlerCallback, long, long, CallbackHandlerDao)}.
+     *
+     * @param directoryName        Name of directory for listen.
+     * @param fileHandlerCallback  File handler for processing.
+     * @param timeoutMillis        Timeout waiting for the file creation in milliseconds.
+     * @param fileLengthCheckDelay Timeout waiting for the file writing in milliseconds.
+     * @param fileName             file name.
+     * @param callbackHandlerDao   callbackHandlerDao for handlers
+     * @return Instance of the file handler.
+     */
+    public static WatchItem listen(String directoryName, FileHandlerCallback fileHandlerCallback, long timeoutMillis,
+                                   long fileLengthCheckDelay, String fileName, CallbackHandlerDao callbackHandlerDao) {
+        FolderListener listener;
+        WatchItem item;
+
+        LOGGER.trace("Looking for folder listener to folder \"{}\" ...", directoryName);
+        synchronized (listeners) {
+            for (int i = 0; i < listeners.size(); i++) {
+                listener = listeners.get(i);
+                if (listener.itemList.getDirectoryName().equals(directoryName)) {
+                    if (listener.isAlive()) {
+                        LOGGER.debug("Folder listener \"{}\" found. Append file handler for UUID {}",
+                                directoryName, fileHandlerCallback.getUUID());
+                        item = listener.itemList.append(fileHandlerCallback, timeoutMillis, fileLengthCheckDelay,
+                                fileName);
+                        return item;
+                    } else {
+                        LOGGER.warn("Folder listener \"{}\" is dead and will be removed", directoryName);
+                        listeners.remove(i);
+                        break;
+                    }
+                }
+            }
+            LOGGER.debug("Folder listener \"{}\" not found. Create new listener and append file handler for UUID {}",
+                    directoryName, fileHandlerCallback.getUUID());
+            listener = new FolderListener(directoryName, callbackHandlerDao);
+            item = listener.itemList.append(fileHandlerCallback, timeoutMillis, fileLengthCheckDelay, fileName);
+            listeners.add(listener);
+            listener.start();
+        }
+        return item;
+    }
+
+    /**
+     * Terminates all the folder listeners.
+     */
+    public static void terminateAll() {
+        FolderListener[] array;
+        synchronized (listeners) {
+            array = listeners.toArray(new FolderListener[listeners.size()]);
+        }
+        for (int i = 0; i < array.length; i++) {
+            array[i].terminate();
+        }
+    }
+
+    /**
+     * Returns the list of folder listeners.
+     */
+    public static List<FolderListener> getListeners() {
+        return listeners;
+    }
+
+    /**
+     * Starts the thread of the folder listener.
+     */
+    protected void start() {
+        thread = new Thread(this, getClass().getSimpleName() + "-" + listeners.size());
+        thread.start();
+    }
+
+    /**
+     * Terminates the thread of the folder listener.
+     */
+    protected void terminate() {
+        if (thread != null) {
+            LOGGER.debug("Folder listener \"{}\" will be terminate", getDirectoryName());
+            thread.interrupt();
+        }
+    }
+
+    /**
+     * Returns <b>true</b> if the folder listener thread is running and is alive, otherwise <b>false</b>.
+     */
+    public boolean isAlive() {
+        return (thread != null && thread.isAlive());
+    }
+
+    /**
+     * Returns <b>true</b> if the folder listener is listening the folder.
+     */
+    public boolean isListen() {
+        return isListen;
+    }
+
+
+    /**
+     * Returns the list of the file handlers.
+     */
+    public WatchItemList getItemList() {
+        return itemList;
+    }
+
+    /**
+     * Returns the full name of directory.
+     */
+    public String getDirectoryName() {
+        return itemList.getDirectoryFullName();
+    }
+
+    /**
+     * Waiting for the directory creation and returns <b>true</b> if it exists or created.
+     * If timeout has expired and directory was not created returns <b>false</b>
+     */
+    private boolean waitForDirectory() throws InterruptedException {
+        File file = new File(getDirectoryName());
+        if (file.exists()) {
+            return true;
+        } else {
+            LOGGER.trace("Folder listener \"{}\" waiting for the directory creation", getDirectoryName());
+        }
+
+        long expiredTimeMillis = itemList.get(0).getExpiredTimeMillis();
+        while (expiredTimeMillis >= System.currentTimeMillis()) {
+            Thread.sleep(WAIT_DIR_TIMEOUT_MILLIS);
+            if (file.exists()) {
+                return true;
+            }
+        }
+        LOGGER.error("Folder listener \"{}\" error. Timeout has expired and directory does not exist",
+                getDirectoryName());
+        return false;
+    }
+
+    /**
+     * Initializes the thread of the folder listener. Returns <b>true</b> if the initialization
+     * completed successfully. Returns <b>false</b> if all the file handlers has been processed
+     * or initialization fails.
+     */
+    private boolean init() {
+        LOGGER.trace("Folder listener initializing for \"{}\" ...", getDirectoryName());
+
+        try {
+            if (!waitForDirectory()) {
+                return false;
+            }
+        } catch (InterruptedException e) {
+            LOGGER.debug("Folder listener \"{}\" has been interrupted", getDirectoryName());
+            Thread.currentThread().interrupt();
+            return false;
+        }
+
+        processStatusItems();
+        if (itemList.size() == 0) {
+            LOGGER.debug("Folder listener \"{}\" have no files and will be finished", getDirectoryName());
+            return false;
+        }
+
+        LOGGER.trace("Folder listener has been initialized for \"{}\" ...", getDirectoryName());
+        return true;
+    }
+
+    /**
+     * Process all the file handlers if need and removes all expired, processed or interrupted
+     * the file handlers from the list of the file handlers.
+     */
+    private void processStatusItems() {
+        int i = 0;
+
+        if (itemList.size() > 0) {
+            expiredIdleMillis = 0;
+        }
+        itemList.processItemAll();
+
+        synchronized (itemList) {
+            while (i < itemList.size()) {
+                final WatchItem item = itemList.get(i);
+                final ItemStatus status = item.getStatus();
+                final String uuid = item.getFileHandlerCallback().getUUID();
+
+                switch (status) {
+                    case WAIT_FOR_FILE:
+                    case FILE_CAPTURED:
+                    case INPROGRESS:
+                        // Skip
+                        i++;
+                        continue;
+                    case TIMEOUT_EXPIRED:
+                        LOGGER.warn("Folder listener \"{}\" remove expired file handler for UUID {}", getDirectoryName
+                                (), uuid);
+                        try {
+                            item.getFileHandlerCallback().handleError("Request timeout expired");
+                        } catch (Exception e) {
+                            LOGGER.error("Folder listener \"{}\" caused exception for UUID {}", getDirectoryName(),
+                                    uuid, e);
+                        }
+                        break;
+                    case IS_DONE:
+                        if (item.getFutureResult()) {
+                            LOGGER.trace("Folder listener \"{}\" remove processed file handler for UUID {}, handler " +
+                                    "result is {}", getDirectoryName(), uuid, item.getFutureResult());
+                        } else {
+                            LOGGER.warn("Folder listener \"{}\" remove processed file handler for UUID {}, handler " +
+                                    "result is {}", getDirectoryName(), uuid, item.getFutureResult());
+                        }
+                        break;
+                    case IS_CANCELED:
+                        LOGGER.debug("Folder listener \"{}\" remove canceled file handler for UUID {}",
+                                getDirectoryName(), uuid);
+                        break;
+                    case IS_FAILED:
+                        LOGGER.warn("Folder listener \"{}\" remove failed file handler for UUID {}", getDirectoryName
+                                (), uuid);
+                        break;
+                    case IS_INTERRUPTED:
+                        LOGGER.debug("Folder listener \"{}\" remove iterrupted file handler for UUID {}",
+                                getDirectoryName(), uuid);
+                        break;
+                    default:
+                        continue;
+                }
+                itemList.remove(i);
+            }
+        }
+
+        if (expiredIdleMillis == 0 && itemList.size() == 0) {
+            expiredIdleMillis = System.currentTimeMillis() + LISTENER_IDLE_TIMEOUT_MILLLIS;
+        }
+    }
+
+    /**
+     * Removes the listener from the list of folder listeners if the the file handler list is empty
+     * and idle time has expired or if <b>force</b> flag has been set to <b>true</b>.
+     *
+     * @param force the flag of remove the folder listener immediately.
+     * @return <b>true</b> if the folder listener has been removed otherwise <b>false</>.
+     */
+    private boolean removeListener(boolean force) {
+        synchronized (listeners) {
+            if (force || (expiredIdleMillis != 0 && expiredIdleMillis < System.currentTimeMillis())) {
+                for (int i = 0; i < listeners.size(); i++) {
+                    if (listeners.get(i) == this) {
+                        isListen = false;
+                        listeners.remove(i);
+                        LOGGER.debug("Folder listener \"{}\" has been removed from pool", getDirectoryName());
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Find and return the list of files to process.
+     */
+    private String[] getNewFiles() {
+        File dir = new File(getDirectoryName());
+        return dir.list((File dir1, String name) -> {
+            if (name.toLowerCase().endsWith(JSON_EXTENSION)) {
+                WatchItem item = itemList.getItem(name);
+                return (item != null && item.getStatus() == ItemStatus.WAIT_FOR_FILE);
+            }
+            return false;
+        });
+    }
+
+    /**
+     * Waiting for files and process it.
+     */
+    private void pollFile() {
+        try {
+            isListen = true;
+            while (true) {
+                String[] fileList = getNewFiles();
+                if (fileList != null) {
+                    for (String fileName : fileList) {
+                        LOGGER.trace("Folder listener \"{}\" handes the file {}", getDirectoryName(), fileName);
+                        processItem(fileName);
+                    }
+                }
+
+                processStatusItems();
+                if (removeListener(false)) {
+                    LOGGER.debug("Folder listener \"{}\" have no files and will be finished", getDirectoryName());
+                    break;
+                }
+                Thread.sleep(LISTENER_TIMEOUT_MILLLIS);
+            }
+        } catch (InterruptedException e) {
+            removeListener(true);
+            LOGGER.debug("Folder listener \"{}\" has been interrupted", getDirectoryName());
+            Thread.currentThread().interrupt();
+        } catch (Exception e) {
+            removeListener(true);
+            LOGGER.error("Folder listener for \"{}\" closed with error.", getDirectoryName(), e);
+            throw new DatalabException("Folder listener for \"" + getDirectoryName() + "\" closed with error. " + e
+                    .getLocalizedMessage(), e);
+        }
+    }
+
+    private void processItem(String fileName) {
+        try {
+            WatchItem item = itemList.getItem(fileName);
+            item.setFileName(fileName);
+            if (itemList.processItem(item)) {
+                LOGGER.debug("Folder listener \"{}\" processes the file {}", getDirectoryName(),
+                        fileName);
+            }
+        } catch (Exception e) {
+            LOGGER.warn("Folder listener \"{}\" has got exception for check or process the file {}",
+                    getDirectoryName(), fileName, e);
+        }
+    }
+
+    @Override
+    public void run() {
+        if (init()) {
+            pollFile();
+        } else {
+            LOGGER.warn("Folder listener has not been initialized for \"{}\"", getDirectoryName());
+            removeListener(true);
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/FolderListenerExecutor.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/FolderListenerExecutor.java
new file mode 100644
index 0000000..7462b80
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/FolderListenerExecutor.java
@@ -0,0 +1,55 @@
+/*
+ * 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.datalab.backendapi.core.response.folderlistener;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import io.dropwizard.util.Duration;
+
+import static com.epam.datalab.backendapi.core.response.folderlistener.FolderListener.listen;
+
+/**
+ * Starts asynchronously of waiting for file creation and processing this file.
+ */
+@Singleton
+public class FolderListenerExecutor {
+    @Inject
+    private ProvisioningServiceApplicationConfiguration configuration;
+    @Inject
+    private CallbackHandlerDao handlerDao;
+
+    /**
+     * Starts asynchronously of waiting for file creation and processes this file if the timeout
+     * has not expired. If timeout has been expired then writes warning message to log file and
+     * finishes waiting. This method is <b>non-blocking</b>.
+     *
+     * @param directory           name of directory for waiting for the file creation.
+     * @param timeout             timeout for waiting.
+     * @param fileHandlerCallback handler for the file processing.
+     */
+    public void start(String directory, Duration timeout, FileHandlerCallback fileHandlerCallback) {
+        CallbackHandlerDao dao = configuration.isHandlersPersistenceEnabled() ? handlerDao : null;
+        listen(directory, fileHandlerCallback, timeout.toMilliseconds(),
+                configuration.getFileLengthCheckDelay().toMilliseconds(), dao);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/WatchItem.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/WatchItem.java
new file mode 100644
index 0000000..5b345f1
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/WatchItem.java
@@ -0,0 +1,258 @@
+/*
+ * 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.datalab.backendapi.core.response.folderlistener;
+
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.google.common.base.MoreObjects;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Class to store the file handler for processing.
+ */
+@Slf4j
+public class WatchItem implements Comparable<WatchItem> {
+
+    /**
+     * Status of file processing.
+     * <pre>
+     * WAIT_FOR_FILE waiting for the file creation.
+     * TIMEOUT_EXPIRED the timeout expired for the file creation.
+     * FILE_CAPTURED the file created and handled.
+     * INPROGRESS the file processing is running.
+     * IS_DONE the file processing is done. You can check the result of processing {@link WatchItem#getFutureResult()}
+     * IS_CANCELED the file processing has been canceled.
+     * IS_INTERRUPTED the file processing has been interrupted.
+     * IS_FAILED the file processing is failed.
+     * </pre>
+     */
+    public enum ItemStatus {
+        WAIT_FOR_FILE,
+        TIMEOUT_EXPIRED,
+        FILE_CAPTURED,
+        INPROGRESS,
+        IS_DONE,
+        IS_CANCELED,
+        IS_INTERRUPTED,
+        IS_FAILED
+    }
+
+    /**
+     * File handler for processing.
+     */
+    private final FileHandlerCallback fileHandlerCallback;
+    /**
+     * Timeout waiting for the file creation in milliseconds.
+     */
+    private final long timeoutMillis;
+    /**
+     * Timeout waiting for the file writing in milliseconds.
+     */
+    private final long fileLengthCheckDelay;
+
+    /**
+     * Time when expired for the file creation in milliseconds.
+     */
+    private long expiredTimeMillis;
+    /**
+     * File name.
+     */
+    private String fileName;
+    /**
+     * Future for asynchronously the file processing.
+     */
+    private CompletableFuture<Boolean> future;
+    /**
+     * Result of the file processing.
+     */
+    private Boolean futureResult = null;
+
+    /**
+     * Creates instance of the file handler.
+     *
+     * @param fileHandlerCallback  File handler for processing.
+     * @param timeoutMillis        Timeout waiting for the file creation in milliseconds.
+     * @param fileLengthCheckDelay Timeout waiting for the file writing in milliseconds.
+     */
+    public WatchItem(FileHandlerCallback fileHandlerCallback, long timeoutMillis, long fileLengthCheckDelay) {
+        this.fileHandlerCallback = fileHandlerCallback;
+        this.timeoutMillis = timeoutMillis;
+        this.fileLengthCheckDelay = fileLengthCheckDelay;
+        setExpiredTimeMillis(timeoutMillis);
+    }
+
+    @Override
+    public int compareTo(WatchItem o) {
+        if (o == null) {
+            return -1;
+        }
+        return (fileHandlerCallback.checkUUID(o.fileHandlerCallback.getUUID()) ?
+                0 : fileHandlerCallback.getUUID().compareTo(o.fileHandlerCallback.getUUID()));
+    }
+
+    /**
+     * Returns the file handler for processing.
+     */
+    public FileHandlerCallback getFileHandlerCallback() {
+        return fileHandlerCallback;
+    }
+
+    /**
+     * Returns the timeout waiting for the file creation in milliseconds.
+     */
+    public long getTimeoutMillis() {
+        return timeoutMillis;
+    }
+
+    /**
+     * Returns the timeout waiting for the file writing in milliseconds.
+     */
+    public long getFileLengthCheckDelay() {
+        return fileLengthCheckDelay;
+    }
+
+
+    /**
+     * Returns the time when expired for the file creation in milliseconds.
+     */
+    public long getExpiredTimeMillis() {
+        return expiredTimeMillis;
+    }
+
+    /**
+     * Sets time when expired for file creation in milliseconds.
+     *
+     * @param expiredTimeMillis time expired for file creation in milliseconds.
+     */
+    private void setExpiredTimeMillis(long expiredTimeMillis) {
+        this.expiredTimeMillis = System.currentTimeMillis() + expiredTimeMillis;
+    }
+
+    /**
+     * Returns the file name.
+     */
+    public String getFileName() {
+        return fileName;
+    }
+
+    /**
+     * Sets the file name.
+     *
+     * @param fileName file name.
+     */
+    protected void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+
+    /**
+     * Returns the status of the file processing.
+     * See {@link ItemStatus} for details.
+     */
+    public ItemStatus getStatus() {
+        if (fileName == null) {
+            return (expiredTimeMillis < System.currentTimeMillis() ? ItemStatus.TIMEOUT_EXPIRED : ItemStatus.WAIT_FOR_FILE);
+        } else if (future == null) {
+            return ItemStatus.FILE_CAPTURED;
+        } else if (future.isCancelled()) {
+            return ItemStatus.IS_CANCELED;
+        }
+
+        if (future.isDone()) {
+            try {
+                futureResult = future.get();
+                return ItemStatus.IS_DONE;
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                return ItemStatus.IS_INTERRUPTED;
+            } catch (ExecutionException e) {
+                log.error("Execution exception occurred", e);
+                return ItemStatus.IS_FAILED;
+            }
+        }
+
+        return ItemStatus.INPROGRESS;
+    }
+
+    /**
+     * Returns <b>true</> if the time has expired for the file creation.
+     */
+    public boolean isExpired() {
+        return (fileName == null && expiredTimeMillis < System.currentTimeMillis());
+    }
+
+
+    /**
+     * Returns the future for asynchronously the file processing.
+     */
+    public CompletableFuture<Boolean> getFuture() {
+        return future;
+    }
+
+    /**
+     * Sets the future for the file processing.
+     *
+     * @param future completable future for file processing.
+     */
+    protected void setFuture(CompletableFuture<Boolean> future) {
+        this.future = future;
+    }
+
+    /**
+     * Returns the result of the file processing. This method is non-blocking and returns <b>true</b>
+     * or <b>false</b> if the file processing has done, otherwise returns <b>null</b>.
+     */
+    public Boolean getFutureResult() {
+        if (futureResult == null && future != null && future.isDone()) {
+            try {
+                futureResult = future.get();
+            } catch (Exception e) {
+                log.error("Exception occurred during getting result: {}", e.getMessage(), e);
+            }
+        }
+        return futureResult;
+    }
+
+    /**
+     * Returns the result of the file processing. This method is blocking and returns <b>true</b> or
+     * <b>false</b> when the file processing has done.
+     */
+    public Boolean getFutureResultSync() throws InterruptedException, ExecutionException {
+        if (futureResult == null && future != null) {
+            futureResult = future.get();
+        }
+        return futureResult;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("fileHandlerCallback", fileHandlerCallback)
+                .add("timeoutMillis", timeoutMillis)
+                .add("fileLengthCheckDelay", fileLengthCheckDelay)
+                .add("expiredTimeMillis", expiredTimeMillis)
+                .add("fileName", fileName)
+                .add("future", future)
+                .add("futureResult", futureResult)
+                .toString();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/WatchItemList.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/WatchItemList.java
new file mode 100644
index 0000000..36e168c
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/folderlistener/WatchItemList.java
@@ -0,0 +1,277 @@
+/*
+ * 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.datalab.backendapi.core.response.folderlistener;
+
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.response.folderlistener.WatchItem.ItemStatus;
+import com.epam.datalab.backendapi.core.response.handlers.PersistentFileHandler;
+import com.epam.datalab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
+import io.dropwizard.util.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Vector;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ForkJoinPool;
+
+/**
+ * List of the file handlers for processing.
+ */
+public class WatchItemList {
+    private static final Logger LOGGER = LoggerFactory.getLogger(WatchItemList.class);
+
+    /**
+     * Directory name.
+     */
+    private final String directoryName;
+    /**
+     * Directory full name.
+     */
+    private final String directoryFullName;
+    private final CallbackHandlerDao handlerDao;
+
+    /**
+     * List of the file handlers.
+     */
+    private final Vector<WatchItem> list = new Vector<>();
+
+    /**
+     * UUID of the file handler for search.
+     */
+    private String uuidSearch;
+
+    /**
+     * File handler for search.
+     */
+    private final FileHandlerCallback handlerSearch = new FileHandlerCallback() {
+        @Override
+        public String getUUID() {
+            return uuidSearch;
+        }
+
+        @Override
+        public boolean checkUUID(String uuid) {
+            return uuidSearch.equals(uuid);
+        }
+
+        @Override
+        public void handleError(String errorMessage) {
+        }
+
+        @Override
+        public String getUser() {
+            return "DATALAB";
+        }
+
+        @Override
+        public boolean handle(String fileName, byte[] content) throws Exception {
+            return false;
+        }
+    };
+
+    /**
+     * Creates instance of the file handlers for processing.
+     *
+     * @param directoryName listener directory name.
+     * @param handlerDao    data access object for callback handler
+     */
+    public WatchItemList(String directoryName, CallbackHandlerDao handlerDao) {
+        this.directoryName = directoryName;
+        this.directoryFullName = Paths.get(directoryName).toAbsolutePath().toString();
+        this.handlerDao = handlerDao;
+    }
+
+    /**
+     * Returns directory name.
+     */
+    public String getDirectoryName() {
+        return directoryName;
+    }
+
+    /**
+     * Returns directory full name.
+     */
+    public String getDirectoryFullName() {
+        return directoryFullName;
+    }
+
+
+    /**
+     * Appends the file handler to the list and returns it.
+     *
+     * @param fileHandlerCallback  File handler for processing.
+     * @param timeoutMillis        Timeout waiting for the file creation in milliseconds.
+     * @param fileLengthCheckDelay Timeout waiting for the file writing in milliseconds.
+     * @return Instance of the file handler.
+     */
+    public WatchItem append(FileHandlerCallback fileHandlerCallback, long timeoutMillis, long fileLengthCheckDelay) {
+        if (Objects.nonNull(handlerDao)) {
+            handlerDao.upsert(new PersistentFileHandler(fileHandlerCallback, timeoutMillis, directoryName));
+        }
+        WatchItem item = new WatchItem(fileHandlerCallback, timeoutMillis, fileLengthCheckDelay);
+        synchronized (this) {
+            int index = Collections.binarySearch(list, item);
+            if (index < 0) {
+                index = -index;
+                if (index > list.size()) {
+                    list.add(item);
+                } else {
+                    list.add(index - 1, item);
+                }
+            } else {
+                LOGGER.warn("Handler for UUID {} for folder {} will be replaced. Old item is: {}",
+                        fileHandlerCallback.getUUID(), directoryFullName, get(index));
+                list.set(index, item);
+            }
+        }
+        return item;
+    }
+
+    /**
+     * Appends the file handler to the list for the existing file and returns it. If the file name
+     * is <b>null</b> this means that file does not exist and equal to call method
+     * {@link WatchItemList#append(FileHandlerCallback, long, long)}.
+     *
+     * @param fileHandlerCallback  File handler for processing.
+     * @param timeoutMillis        Timeout waiting for the file creation in milliseconds.
+     * @param fileLengthCheckDelay Timeout waiting for the file writing in milliseconds.
+     * @param fileName             file name.
+     * @return Instance of file handler.
+     */
+    public WatchItem append(FileHandlerCallback fileHandlerCallback, long timeoutMillis, long fileLengthCheckDelay,
+                            String fileName) {
+        WatchItem item = append(fileHandlerCallback, timeoutMillis, fileLengthCheckDelay);
+        if (fileName != null) {
+            item.setFileName(fileName);
+        }
+        return item;
+    }
+
+    /**
+     * Removes the file handler from list.
+     *
+     * @param index index of the file handler.
+     */
+    public void remove(int index) {
+
+        final WatchItem watchItem = list.remove(index);
+        if (Objects.nonNull(handlerDao) && watchItem.getStatus() != ItemStatus.IS_FAILED) {
+            handlerDao.remove(watchItem.getFileHandlerCallback().getId());
+        }
+    }
+
+    /**
+     * Returns the number of the file handlers in list.
+     */
+    public int size() {
+        return list.size();
+    }
+
+    /**
+     * Returns the file handler.
+     *
+     * @param index index of the file handler.
+     */
+    public WatchItem get(int index) {
+        return list.get(index);
+    }
+
+    /**
+     * Returns the index of the file handler in the list if it is contained in the list,
+     * otherwise returns (-(insertion point) - 1).
+     *
+     * @param uuid UUID of the file handler.
+     */
+    public int getIndex(String uuid) {
+        uuidSearch = uuid;
+        return Collections.binarySearch(list, new WatchItem(handlerSearch, 0, 0));
+    }
+
+    /**
+     * Returns the instance of the file handler if it contained in the list,
+     * otherwise returns <b>null</b>.
+     */
+    public WatchItem getItem(String fileName) {
+        String uuid = DockerCommands.extractUUID(fileName);
+        int index = getIndex(uuid);
+        if (index < 0) {
+            return null;
+        }
+        return get(index);
+    }
+
+    /**
+     * Runs asynchronously the file handler in the {@link ForkJoinPool#commonPool()}.
+     *
+     * @param item the file handler.
+     */
+    private void runAsync(WatchItem item) {
+        LOGGER.trace("Process file {} for folder {}", item.getFileName(), directoryFullName);
+        item.setFuture(CompletableFuture.supplyAsync(
+                new AsyncFileHandler(item.getFileName(), getDirectoryName(),
+                        item.getFileHandlerCallback(), Duration.milliseconds(item.getFileLengthCheckDelay()))));
+    }
+
+    /**
+     * Runs the file processing asynchronously if it have status {@link ItemStatus#FILE_CAPTURED} and returns
+     * <b>true</b>,
+     * otherwise <b>false</b>.
+     *
+     * @param item the file handler.
+     */
+    public boolean processItem(WatchItem item) {
+        if (item.getStatus() == ItemStatus.FILE_CAPTURED) {
+            runAsync(item);
+            return true;
+        }
+
+        if (item.isExpired()) {
+            LOGGER.warn("Watch time has expired for UUID {} in folder {}", item.getFileHandlerCallback().getUUID(),
+                    directoryFullName);
+        }
+        return false;
+    }
+
+    /**
+     * Checks all the file handlers and runs the file processing for it if have status
+     * {@link ItemStatus#FILE_CAPTURED}.
+     */
+    public int processItemAll() {
+        int count = 0;
+        synchronized (list) {
+            for (int i = 0; i < size(); i++) {
+                WatchItem item = list.get(i);
+                if (item.getStatus() == ItemStatus.FILE_CAPTURED && processItem(item)) {
+                    count++;
+                }
+            }
+        }
+        if (count > 0) {
+            LOGGER.trace("Starts processing {} files for folder {}", count, directoryName);
+        }
+        return count;
+    }
+
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/BackupCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/BackupCallbackHandler.java
new file mode 100644
index 0000000..40fa2dd
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/BackupCallbackHandler.java
@@ -0,0 +1,126 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.dto.backup.EnvBackupDTO;
+import com.epam.datalab.dto.backup.EnvBackupStatus;
+import com.epam.datalab.dto.backup.EnvBackupStatusDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.fasterxml.jackson.annotation.JacksonInject;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.core.Response;
+
+@Slf4j
+public class BackupCallbackHandler implements FileHandlerCallback {
+    private static final ObjectMapper MAPPER = new ObjectMapper()
+            .configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
+    private static final String STATUS_FIELD = "status";
+    private static final String BACKUP_FILE_FIELD = "backup_file";
+    private static final String ERROR_MESSAGE_FIELD = "error_message";
+    @JsonProperty
+    private final String uuid;
+    @JsonProperty
+    private final EnvBackupDTO dto;
+    private final RESTService selfService;
+    @JsonProperty
+    private final String callbackUrl;
+    @JsonProperty
+    private final String user;
+
+    @JsonCreator
+    public BackupCallbackHandler(
+            @JacksonInject RESTService selfService,
+            @JsonProperty("callbackUrl") String callbackUrl, @JsonProperty("user") String user,
+            @JsonProperty("dto") EnvBackupDTO dto) {
+        this.selfService = selfService;
+        this.uuid = dto.getId();
+        this.callbackUrl = callbackUrl;
+        this.user = user;
+        this.dto = dto;
+    }
+
+    @Override
+    public String getUUID() {
+        return uuid;
+    }
+
+    @Override
+    public boolean checkUUID(String uuid) {
+        return this.uuid.equals(uuid);
+    }
+
+    @Override
+    public boolean handle(String fileName, byte[] content) throws Exception {
+        final String fileContent = new String(content);
+        log.debug("Got file {} while waiting for UUID {}, backup response: {}", fileName, uuid, fileContent);
+
+        final JsonNode jsonNode = MAPPER.readTree(fileContent);
+        final EnvBackupStatus status = EnvBackupStatus.fromValue(jsonNode.get(STATUS_FIELD).textValue());
+        EnvBackupStatusDTO envBackupStatusDTO;
+        if (EnvBackupStatus.CREATED == status) {
+            envBackupStatusDTO = buildBackupStatusDto(EnvBackupStatus.CREATED)
+                    .withBackupFile(jsonNode.get(BACKUP_FILE_FIELD).textValue());
+        } else {
+            envBackupStatusDTO = buildBackupStatusDto(EnvBackupStatus.FAILED)
+                    .withErrorMessage(jsonNode.get(ERROR_MESSAGE_FIELD).textValue());
+        }
+        selfServicePost(envBackupStatusDTO);
+        return EnvBackupStatus.CREATED == status;
+    }
+
+    private void selfServicePost(EnvBackupStatusDTO statusDTO) {
+        log.debug("Send post request to self service {} for UUID {}, object is {}", uuid, statusDTO);
+        try {
+            selfService.post(callbackUrl, statusDTO, Response.class);
+        } catch (Exception e) {
+            log.error("Send request or response error for UUID {}: {}", uuid, e.getLocalizedMessage(), e);
+            throw new DatalabException("Send request or response error for UUID " + uuid + ": " + e.getLocalizedMessage()
+                    , e);
+        }
+    }
+
+    @Override
+    public void handleError(String errorMessage) {
+        buildBackupStatusDto(EnvBackupStatus.FAILED)
+                .withErrorMessage(errorMessage);
+    }
+
+    @Override
+    public String getUser() {
+        return user;
+    }
+
+    protected EnvBackupStatusDTO buildBackupStatusDto(EnvBackupStatus status) {
+        return new EnvBackupStatusDTO()
+                .withRequestId(uuid)
+                .withEnvBackupDTO(dto)
+                .withStatus(status)
+                .withUser(user);
+    }
+
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/CheckInactivityCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/CheckInactivityCallbackHandler.java
new file mode 100644
index 0000000..8358835
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/CheckInactivityCallbackHandler.java
@@ -0,0 +1,141 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.computational.CheckInactivityStatusDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.fasterxml.jackson.annotation.JacksonInject;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Singleton;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.core.Response;
+
+@Slf4j
+@Singleton
+public class CheckInactivityCallbackHandler implements FileHandlerCallback {
+    private static final ObjectMapper MAPPER = new ObjectMapper()
+            .configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
+    private static final String STATUS_FIELD = "status";
+    private static final String ERROR_MESSAGE_FIELD = "error_message";
+    private static final String RESPONSE = "response";
+    private static final String OK_STATUS_STRING = "ok";
+    private static final String RESULT_NODE = "result";
+    @JsonProperty
+    private final String uuid;
+    private final RESTService selfService;
+    @JsonProperty
+    private final String callbackUrl;
+    @JsonProperty
+    private final String user;
+    @JsonProperty
+    private final String exploratoryName;
+    @JsonProperty
+    private final String computationalName;
+
+    @JsonCreator
+    public CheckInactivityCallbackHandler(@JacksonInject RESTService selfService,
+                                          @JsonProperty("callbackUrl") String callbackUrl,
+                                          @JsonProperty("user") String user, String uuid, String exploratoryName,
+                                          String computationalName) {
+        this.selfService = selfService;
+        this.uuid = uuid;
+        this.callbackUrl = callbackUrl;
+        this.user = user;
+        this.exploratoryName = exploratoryName;
+        this.computationalName = computationalName;
+    }
+
+    public CheckInactivityCallbackHandler(RESTService selfService,
+                                          String callbackUrl, String user, String uuid, String exploratoryName) {
+        this(selfService, callbackUrl, user, uuid, exploratoryName, null);
+    }
+
+    @Override
+    public String getUUID() {
+        return uuid;
+    }
+
+    @Override
+    public boolean checkUUID(String uuid) {
+        return this.uuid.equals(uuid);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public boolean handle(String fileName, byte[] content) throws Exception {
+        final String fileContent = new String(content);
+        log.debug("Got file {} while waiting for UUID {}, check inactivity resources response: {}", fileName, uuid,
+                fileContent);
+
+        final JsonNode treeNode = MAPPER.readTree(fileContent);
+        final String status = treeNode.get(STATUS_FIELD).textValue();
+        CheckInactivityStatusDTO checkInactivityStatusDTO = OK_STATUS_STRING.equals(status) ?
+                getOkStatusDto(treeNode) : getFailedStatusDto(treeNode.get(ERROR_MESSAGE_FIELD).textValue());
+        selfServicePost(checkInactivityStatusDTO);
+        return OK_STATUS_STRING.equals(status);
+    }
+
+    @Override
+    public void handleError(String errorMessage) {
+        log.error(errorMessage);
+        selfServicePost(getFailedStatusDto(errorMessage).withErrorMessage(errorMessage));
+    }
+
+    @Override
+    public String getUser() {
+        return user;
+    }
+
+    private CheckInactivityStatusDTO getOkStatusDto(JsonNode jsonNode) {
+        final CheckInactivityStatusDTO statusDTO = new CheckInactivityStatusDTO().withStatus(OK_STATUS_STRING)
+                .withRequestId(uuid);
+        statusDTO.setComputationalName(computationalName);
+        statusDTO.setExploratoryName(exploratoryName);
+        final long lastActivity = Long.parseLong(jsonNode.get(RESPONSE).get(RESULT_NODE).textValue());
+        statusDTO.setLastActivityUnixTime(lastActivity);
+        return statusDTO;
+    }
+
+    private CheckInactivityStatusDTO getFailedStatusDto(String errorMessage) {
+        return new CheckInactivityStatusDTO().withStatus(UserInstanceStatus.FAILED)
+                .withRequestId(uuid)
+                .withErrorMessage(errorMessage);
+    }
+
+    private void selfServicePost(CheckInactivityStatusDTO statusDTO) {
+        log.debug("Send post request to self service for UUID {}, object is {}", uuid, statusDTO);
+        try {
+            selfService.post(callbackUrl, statusDTO, Response.class);
+        } catch (Exception e) {
+            log.error("Send request or response error for UUID {}: {}", uuid, e.getLocalizedMessage(), e);
+            throw new DatalabException("Send request or response error for UUID " + uuid + ": "
+                    + e.getLocalizedMessage(), e);
+        }
+    }
+
+}
+
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalCallbackHandler.java
new file mode 100644
index 0000000..7e0a549
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalCallbackHandler.java
@@ -0,0 +1,133 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.dto.ResourceURL;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.epam.datalab.dto.computational.ComputationalStatusDTO;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.fasterxml.jackson.annotation.JacksonInject;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+@Slf4j
+public class ComputationalCallbackHandler extends ResourceCallbackHandler<ComputationalStatusDTO> {
+    private static final String INSTANCE_ID_FIELD = "instance_id";
+    private static final String COMPUTATIONAL_ID_FIELD = "hostname";
+    private static final String COMPUTATIONAL_URL_FIELD = "computational_url";
+
+    @JsonProperty
+    private final ComputationalBase<?> dto;
+    private ComputationalConfigure computationalConfigure;
+
+    @JsonCreator
+    public ComputationalCallbackHandler(@JacksonInject ComputationalConfigure computationalConfigure,
+                                        @JacksonInject RESTService selfService,
+                                        @JsonProperty("action") DockerAction action,
+                                        @JsonProperty("uuid") String uuid,
+                                        @JsonProperty("dto") ComputationalBase<?> dto) {
+
+        super(selfService, dto.getCloudSettings().getIamUser(), uuid, action);
+        this.computationalConfigure = computationalConfigure;
+        this.dto = dto;
+    }
+
+    protected ComputationalBase<?> getDto() {
+        return dto;
+    }
+
+    @Override
+    protected String getCallbackURI() {
+        return ApiCallbacks.COMPUTATIONAL + ApiCallbacks.STATUS_URI;
+    }
+
+    @Override
+    protected ComputationalStatusDTO parseOutResponse(JsonNode resultNode, ComputationalStatusDTO baseStatus) {
+        if (resultNode == null) {
+            return baseStatus;
+        }
+        baseStatus.withComputationalUrl(extractUrl(resultNode));
+        baseStatus.withLastActivity(Date.from(Instant.now()));
+
+        if (DockerAction.CREATE == getAction()) {
+            baseStatus
+                    .withInstanceId(instanceId(resultNode.get(INSTANCE_ID_FIELD)))
+                    .withComputationalId(getTextValue(resultNode.get(COMPUTATIONAL_ID_FIELD)));
+            if (UserInstanceStatus.of(baseStatus.getStatus()) == UserInstanceStatus.RUNNING) {
+                baseStatus.withStatus(UserInstanceStatus.CONFIGURING);
+                computationalConfigure.configure(getUUID(), getDto());
+            }
+        }
+        return baseStatus;
+    }
+
+    @Override
+    protected ComputationalStatusDTO getBaseStatusDTO(UserInstanceStatus status) {
+        return super.getBaseStatusDTO(status)
+                .withExploratoryName(dto.getExploratoryName())
+                .withComputationalName(dto.getComputationalName())
+                .withProject(dto.getProject());
+    }
+
+    private String instanceId(JsonNode jsonNode) {
+        if (jsonNode != null && jsonNode.isArray()) {
+            return StreamSupport.stream(jsonNode.spliterator(), false)
+                    .map(JsonNode::textValue)
+                    .collect(Collectors.joining(";"));
+        } else {
+            return getTextValue(jsonNode);
+        }
+
+    }
+
+    private List<ResourceURL> extractUrl(JsonNode resultNode) {
+        final JsonNode nodeUrl = resultNode.get(COMPUTATIONAL_URL_FIELD);
+        return Optional.ofNullable(nodeUrl)
+                .map(this::getUrls)
+                .orElse(Collections.emptyList());
+    }
+
+    private List<ResourceURL> getUrls(JsonNode nodeUrl) {
+        try {
+            return mapper.readValue(nodeUrl.toString(), new TypeReference<List<ResourceURL>>() {
+            });
+        } catch (IOException e) {
+            log.warn("Cannot parse field {} for UUID {} in JSON", RESPONSE_NODE + "." + RESULT_NODE + "." +
+                    COMPUTATIONAL_URL_FIELD, getUUID(), e);
+        }
+        return Collections.emptyList();
+    }
+}
+
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalConfigure.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalConfigure.java
new file mode 100644
index 0000000..3cdfcf2
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalConfigure.java
@@ -0,0 +1,140 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.CommandBuilder;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.ICommandExecutor;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.folderlistener.FolderListenerExecutor;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.aws.computational.SparkComputationalCreateAws;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.epam.datalab.dto.gcp.computational.SparkComputationalCreateGcp;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Objects;
+
+import static com.epam.datalab.backendapi.core.commands.DockerAction.CONFIGURE;
+
+@Slf4j
+@Singleton
+public class ComputationalConfigure implements DockerCommands {
+    @Inject
+    private ProvisioningServiceApplicationConfiguration configuration;
+    @Inject
+    private FolderListenerExecutor folderListenerExecutor;
+    @Inject
+    private ICommandExecutor commandExecutor;
+    @Inject
+    private CommandBuilder commandBuilder;
+    @Inject
+    private RESTService selfService;
+
+    public String configure(String uuid, ComputationalBase<?> dto) {
+        switch (configuration.getCloudProvider()) {
+            case AWS:
+                if (dto instanceof SparkComputationalCreateAws) {
+                    return runConfigure(uuid, dto, DataEngineType.SPARK_STANDALONE);
+                } else {
+                    return runConfigure(uuid, dto, DataEngineType.CLOUD_SERVICE);
+                }
+            case AZURE:
+                return runConfigure(uuid, dto, DataEngineType.SPARK_STANDALONE);
+            case GCP:
+                if (dto instanceof SparkComputationalCreateGcp) {
+                    return runConfigure(uuid, dto, DataEngineType.SPARK_STANDALONE);
+                } else {
+                    return runConfigure(uuid, dto, DataEngineType.CLOUD_SERVICE);
+                }
+
+            default:
+                throw new IllegalStateException(String.format("Wrong configuration of cloud provider %s %s",
+                        configuration.getCloudProvider(), dto));
+        }
+    }
+
+    private String runConfigure(String uuid, ComputationalBase<?> dto, DataEngineType dataEngineType) {
+        log.debug("Configure computational resources {} for user {}: {}", dto.getComputationalName(), dto
+                .getEdgeUserName(), dto);
+        folderListenerExecutor.start(
+                configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallback(CONFIGURE, uuid, dto));
+        try {
+            RunDockerCommand runDockerCommand = new RunDockerCommand()
+                    .withInteractive()
+                    .withName(nameContainer(dto.getEdgeUserName(), CONFIGURE,
+                            dto.getExploratoryName(), dto.getComputationalName()))
+                    .withVolumeForRootKeys(configuration.getKeyDirectory())
+                    .withVolumeForResponse(configuration.getImagesDirectory())
+                    .withVolumeForLog(configuration.getDockerLogDirectory(), dataEngineType.getName())
+                    .withResource(dataEngineType.getName())
+                    .withRequestId(uuid)
+                    .withConfKeyName(configuration.getAdminKey())
+                    .withActionConfigure(getImageConfigure(dto.getApplicationName(), dataEngineType));
+            if (configuration.getCloudProvider() == CloudProvider.AZURE &&
+                    Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
+                    !configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
+                runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
+            }
+
+            commandExecutor.executeAsync(
+                    dto.getEdgeUserName(),
+                    uuid,
+                    commandBuilder.buildCommand(runDockerCommand, dto));
+        } catch (Exception t) {
+            throw new DatalabException("Could not configure computational resource cluster", t);
+        }
+        return uuid;
+    }
+
+    private FileHandlerCallback getFileHandlerCallback(DockerAction action, String originalUuid, ComputationalBase<?>
+            dto) {
+        return new ComputationalConfigureCallbackHandler(selfService, action, originalUuid, dto);
+    }
+
+    private String nameContainer(String user, DockerAction action, String exploratoryName, String name) {
+        return nameContainer(user, action.toString(), "computational", exploratoryName, name);
+    }
+
+    private String getImageConfigure(String application, DataEngineType dataEngineType) {
+        String imageName = DataEngineType.getDockerImageName(dataEngineType);
+        int pos = imageName.indexOf('-');
+        if (pos > 0) {
+            return imageName.substring(0, pos + 1) + application;
+        }
+        throw new DatalabException("Could not describe the image name for computational resources from image " +
+                imageName + " and application " + application);
+    }
+
+    public String getResourceType() {
+        return Directories.DATA_ENGINE_SERVICE_LOG_DIRECTORY;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalConfigureCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalConfigureCallbackHandler.java
new file mode 100644
index 0000000..a32f634
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalConfigureCallbackHandler.java
@@ -0,0 +1,63 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.epam.datalab.dto.computational.ComputationalStatusDTO;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.fasterxml.jackson.annotation.JacksonInject;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.time.Instant;
+import java.util.Date;
+
+public class ComputationalConfigureCallbackHandler extends ResourceCallbackHandler<ComputationalStatusDTO> {
+
+    @JsonProperty
+    private final ComputationalBase<?> dto;
+
+    @JsonCreator
+    public ComputationalConfigureCallbackHandler(@JacksonInject RESTService selfService,
+                                                 @JsonProperty("action") DockerAction action,
+                                                 @JsonProperty("uuid") String uuid,
+                                                 @JsonProperty("dto") ComputationalBase<?> dto) {
+        super(selfService, dto.getCloudSettings().getIamUser(), uuid, action);
+        this.dto = dto;
+    }
+
+    @Override
+    protected String getCallbackURI() {
+        return ApiCallbacks.COMPUTATIONAL + ApiCallbacks.STATUS_URI;
+    }
+
+    @Override
+    protected ComputationalStatusDTO parseOutResponse(JsonNode resultNode, ComputationalStatusDTO baseStatus) {
+        return baseStatus
+                .withExploratoryName(dto.getExploratoryName())
+                .withComputationalName(dto.getComputationalName())
+                .withProject(dto.getProject())
+                .withUptime(null)
+                .withLastActivity(Date.from(Instant.now()));
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/EdgeCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/EdgeCallbackHandler.java
new file mode 100644
index 0000000..4c20794
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/EdgeCallbackHandler.java
@@ -0,0 +1,78 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import com.epam.datalab.dto.base.keyload.UploadFileResult;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.fasterxml.jackson.annotation.JacksonInject;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.io.IOException;
+
+public class EdgeCallbackHandler<E extends EdgeInfo, T extends UploadFileResult<E>> extends ResourceCallbackHandler<T> {
+    @JsonProperty
+    private final String callbackURI;
+    @JsonProperty
+    private final Class<E> responseType;
+
+    @JsonCreator
+    public EdgeCallbackHandler(
+            @JacksonInject RESTService selfService, @JsonProperty("action") DockerAction action,
+            @JsonProperty("uuid") String uuid, @JsonProperty("user") String user,
+            @JsonProperty("callbackURI") String callbackURI,
+            @JsonProperty("responseType") Class<E> responseType,
+            @JsonProperty("resultType") Class<T> enclosingType) {
+
+        super(selfService, user, uuid, action, enclosingType);
+        this.callbackURI = callbackURI;
+        this.responseType = responseType;
+    }
+
+    @Override
+    protected String getCallbackURI() {
+        return callbackURI;
+    }
+
+    protected T parseOutResponse(JsonNode resultNode, T baseStatus) {
+        if (resultNode != null && getAction() == DockerAction.CREATE
+                && UserInstanceStatus.of(baseStatus.getStatus()) != UserInstanceStatus.FAILED) {
+            try {
+                E credential = mapper.readValue(resultNode.toString(), responseType);
+                credential.setEdgeStatus(UserInstanceStatus.RUNNING.toString());
+                baseStatus.withEdgeInfo(credential);
+            } catch (IOException e) {
+                throw new DatalabException("Cannot parse the EDGE info in JSON: " + e.getLocalizedMessage(), e);
+            }
+        }
+
+        return baseStatus;
+    }
+
+    @Override
+    public void handleError(String errorMessage) {
+        super.handleError("Could not upload the user key: " + errorMessage);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ExploratoryCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ExploratoryCallbackHandler.java
new file mode 100644
index 0000000..8bdabe1
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ExploratoryCallbackHandler.java
@@ -0,0 +1,108 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.dto.ResourceURL;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.exploratory.ExploratoryStatusDTO;
+import com.epam.datalab.rest.client.RESTService;
+import com.fasterxml.jackson.annotation.JacksonInject;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.List;
+
+import static com.epam.datalab.rest.contracts.ApiCallbacks.EXPLORATORY;
+import static com.epam.datalab.rest.contracts.ApiCallbacks.STATUS_URI;
+
+public class ExploratoryCallbackHandler extends ResourceCallbackHandler<ExploratoryStatusDTO> {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ExploratoryCallbackHandler.class);
+
+    private static final String INSTANCE_ID_FIELD = "instance_id";
+    private static final String EXPLORATORY_ID_FIELD = "notebook_name";
+    private static final String EXPLORATORY_PRIVATE_IP_FIELD = "ip";
+    private static final String EXPLORATORY_URL_FIELD = "exploratory_url";
+    private static final String EXPLORATORY_USER_FIELD = "exploratory_user";
+    private static final String EXPLORATORY_PASSWORD_FIELD = "exploratory_pass";
+
+    @JsonProperty
+    private final String exploratoryName;
+    private final String project;
+
+    @JsonCreator
+    public ExploratoryCallbackHandler(@JacksonInject RESTService selfService,
+                                      @JsonProperty("action") DockerAction action,
+                                      @JsonProperty("uuid") String uuid, @JsonProperty("user") String user,
+                                      String project, @JsonProperty("exploratoryName") String exploratoryName) {
+        super(selfService, user, uuid, action);
+        this.exploratoryName = exploratoryName;
+        this.project = project;
+    }
+
+    @Override
+    protected String getCallbackURI() {
+        return EXPLORATORY + STATUS_URI;
+    }
+
+    @Override
+    protected ExploratoryStatusDTO parseOutResponse(JsonNode resultNode, ExploratoryStatusDTO baseStatus) {
+        if (resultNode == null) {
+            return baseStatus;
+        }
+        final JsonNode nodeUrl = resultNode.get(EXPLORATORY_URL_FIELD);
+        List<ResourceURL> url = null;
+        if (nodeUrl != null) {
+            try {
+                url = mapper.readValue(nodeUrl.toString(), new TypeReference<List<ResourceURL>>() {
+                });
+            } catch (IOException e) {
+                LOGGER.warn("Cannot parse field {} for UUID {} in JSON",
+                        RESPONSE_NODE + "." + RESULT_NODE + "." + EXPLORATORY_URL_FIELD, getUUID(), e);
+            }
+        }
+
+        String exploratoryId = getTextValue(resultNode.get(EXPLORATORY_ID_FIELD));
+        if (getAction() == DockerAction.CREATE && exploratoryId == null) {
+            LOGGER.warn("Empty field {} for UUID {} in JSON", String.format("%s.%s.%s", RESPONSE_NODE, RESULT_NODE,
+                    EXPLORATORY_ID_FIELD), getUUID());
+        }
+
+        return baseStatus
+                .withInstanceId(getTextValue(resultNode.get(INSTANCE_ID_FIELD)))
+                .withExploratoryId(exploratoryId)
+                .withExploratoryUrl(url)
+                .withPrivateIp(getTextValue(resultNode.get(EXPLORATORY_PRIVATE_IP_FIELD)))
+                .withExploratoryUser(getTextValue(resultNode.get(EXPLORATORY_USER_FIELD)))
+                .withExploratoryPassword(getTextValue(resultNode.get(EXPLORATORY_PASSWORD_FIELD)));
+    }
+
+    @Override
+    protected ExploratoryStatusDTO getBaseStatusDTO(UserInstanceStatus status) {
+        return super.getBaseStatusDTO(status)
+                .withExploratoryName(exploratoryName)
+                .withProject(project);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ExploratoryGitCredsCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ExploratoryGitCredsCallbackHandler.java
new file mode 100644
index 0000000..8cde822
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ExploratoryGitCredsCallbackHandler.java
@@ -0,0 +1,65 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.exploratory.ExploratoryStatusDTO;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.fasterxml.jackson.annotation.JacksonInject;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class ExploratoryGitCredsCallbackHandler extends ResourceCallbackHandler<ExploratoryStatusDTO> {
+
+    @JsonProperty
+    private final String exploratoryName;
+
+    @JsonCreator
+    public ExploratoryGitCredsCallbackHandler(@JacksonInject RESTService selfService,
+                                              @JsonProperty("action") DockerAction action,
+                                              @JsonProperty("uuid") String uuid,
+                                              @JsonProperty("user") String user,
+                                              @JsonProperty("exploratoryName") String exploratoryName) {
+        super(selfService, user, uuid, action);
+        this.exploratoryName = exploratoryName;
+    }
+
+    @Override
+    protected String getCallbackURI() {
+        return ApiCallbacks.GIT_CREDS;
+    }
+
+    @Override
+    protected ExploratoryStatusDTO parseOutResponse(JsonNode resultNode, ExploratoryStatusDTO baseStatus) {
+        log.trace("Parse GIT Creds: {}", resultNode);
+        return baseStatus;
+    }
+
+    @Override
+    protected ExploratoryStatusDTO getBaseStatusDTO(UserInstanceStatus status) {
+        return super.getBaseStatusDTO(status)
+                .withExploratoryName(exploratoryName);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ImageCreateCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ImageCreateCallbackHandler.java
new file mode 100644
index 0000000..2b15b0a
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ImageCreateCallbackHandler.java
@@ -0,0 +1,106 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.exploratory.ExploratoryImageDTO;
+import com.epam.datalab.dto.exploratory.ImageCreateStatusDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.fasterxml.jackson.annotation.JacksonInject;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+
+@Slf4j
+public class ImageCreateCallbackHandler extends ResourceCallbackHandler<ImageCreateStatusDTO> {
+    @JsonProperty
+    private final String imageName;
+    @JsonProperty
+    private final String exploratoryName;
+    @JsonProperty
+    private final String project;
+    @JsonProperty
+    private final String endpoint;
+
+    public ImageCreateCallbackHandler(RESTService selfService, String uuid, DockerAction action,
+                                      ExploratoryImageDTO image) {
+        super(selfService, image.getCloudSettings().getIamUser(), uuid, action);
+        this.imageName = image.getImageName();
+        this.exploratoryName = image.getExploratoryName();
+        this.project = image.getProject();
+        this.endpoint = image.getEndpoint();
+    }
+
+    @JsonCreator
+    private ImageCreateCallbackHandler(
+            @JacksonInject RESTService selfService, @JsonProperty("uuid") String uuid,
+            @JsonProperty("action") DockerAction action,
+            @JsonProperty("user") String user,
+            @JsonProperty("imageName") String imageName,
+            @JsonProperty("exploratoryName") String exploratoryName,
+            @JsonProperty("project") String projectName,
+            @JsonProperty("endpoint") String endpoint) {
+        super(selfService, user, uuid, action);
+        this.imageName = imageName;
+        this.exploratoryName = exploratoryName;
+        this.project = projectName;
+        this.endpoint = endpoint;
+    }
+
+    @Override
+    protected String getCallbackURI() {
+        return ApiCallbacks.IMAGE_STATUS_URI;
+    }
+
+    @Override
+    protected ImageCreateStatusDTO parseOutResponse(JsonNode document, ImageCreateStatusDTO statusDTO) {
+        if (document != null) {
+            statusDTO.withImageCreateDto(toImageCreateDto(document.toString()));
+        }
+        return statusDTO;
+    }
+
+    @Override
+    protected ImageCreateStatusDTO getBaseStatusDTO(UserInstanceStatus status) {
+        final ImageCreateStatusDTO statusDTO = super.getBaseStatusDTO(status);
+        statusDTO.setExploratoryName(exploratoryName);
+        statusDTO.setName(imageName);
+        statusDTO.setProject(project);
+        statusDTO.setEndpoint(endpoint);
+        statusDTO.withoutImageCreateDto();
+        return statusDTO;
+    }
+
+    private ImageCreateStatusDTO.ImageCreateDTO toImageCreateDto(String content) {
+        try {
+            return mapper.readValue(content, ImageCreateStatusDTO.ImageCreateDTO.class);
+        } catch (IOException e) {
+            log.error("Can't parse create image response with content {} for uuid {}", content, getUUID());
+            throw new DatalabException(String.format("Can't parse create image response with content %s for uuid %s",
+                    content, getUUID()), e);
+        }
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/LibInstallCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/LibInstallCallbackHandler.java
new file mode 100644
index 0000000..6ddfc00
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/LibInstallCallbackHandler.java
@@ -0,0 +1,118 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.exploratory.LibInstallDTO;
+import com.epam.datalab.dto.exploratory.LibInstallStatusDTO;
+import com.epam.datalab.dto.exploratory.LibraryInstallDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.fasterxml.jackson.annotation.JacksonInject;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Handler of docker response for the request for libraries installation.
+ */
+@Slf4j
+public class LibInstallCallbackHandler extends ResourceCallbackHandler<LibInstallStatusDTO> {
+
+    /**
+     * Name of node in response "Libs".
+     */
+    private static final String LIBS = "Libs";
+
+    /**
+     * Full name of node in response "Libs".
+     */
+    private static final String LIBS_ABSOLUTE_PATH = RESPONSE_NODE + "." + RESULT_NODE + "." + LIBS;
+
+    /**
+     * Exploratory DTO.
+     */
+    @JsonProperty
+    private final LibraryInstallDTO dto;
+
+    /**
+     * Instantiate handler for process of docker response for libraries installation.
+     *
+     * @param selfService REST pointer for Self Service.
+     * @param action      docker action.
+     * @param uuid        request UID.
+     * @param dto         contains libraries to instal
+     */
+    @JsonCreator
+    public LibInstallCallbackHandler(
+            @JacksonInject RESTService selfService,
+            @JsonProperty("action") DockerAction action,
+            @JsonProperty("uuid") String uuid, @JsonProperty("user") String user,
+            @JsonProperty("dto") LibraryInstallDTO dto) {
+        super(selfService, user, uuid, action);
+        this.dto = dto;
+    }
+
+    @Override
+    protected String getCallbackURI() {
+        return ApiCallbacks.LIB_STATUS_URI;
+    }
+
+    @Override
+    protected LibInstallStatusDTO parseOutResponse(JsonNode resultNode, LibInstallStatusDTO status) {
+
+        if (UserInstanceStatus.FAILED == UserInstanceStatus.of(status.getStatus()) || resultNode == null) {
+            throw new DatalabException("Can't handle response result node is null or response status is failed");
+        }
+
+        JsonNode nodeLibs = resultNode.get(LIBS);
+        if (nodeLibs == null) {
+            throw new DatalabException("Can't handle response without property " + LIBS_ABSOLUTE_PATH);
+        }
+        try {
+            final List<LibInstallDTO> libs = mapper.readValue(nodeLibs.toString(),
+                    new TypeReference<List<LibInstallDTO>>() {
+                    });
+            status.withLibs(libs);
+        } catch (IOException e) {
+            log.warn("Can't parse field {} for UUID {} in JSON", LIBS_ABSOLUTE_PATH, getUUID(), e);
+        }
+
+        return status;
+    }
+
+    @Override
+    protected LibInstallStatusDTO getBaseStatusDTO(UserInstanceStatus status) {
+        return super.getBaseStatusDTO(status)
+                .withExploratoryName(dto.getExploratoryName())
+                .withComputationalName(dto.getComputationalName())
+                .withProject(dto.getProject())
+                .withUptime(Date.from(Instant.now()));
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/LibListCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/LibListCallbackHandler.java
new file mode 100644
index 0000000..04efa6a
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/LibListCallbackHandler.java
@@ -0,0 +1,110 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.exploratory.LibListStatusDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.fasterxml.jackson.annotation.JacksonInject;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Handler of docker response for the request the list of libraries.
+ */
+public class LibListCallbackHandler extends ResourceCallbackHandler<LibListStatusDTO> {
+
+    /**
+     * Name of node in response "file".
+     */
+    private static final String FILE = "file";
+
+    /**
+     * The name of docker image.
+     */
+    @JsonProperty
+    private final String group;
+
+    /**
+     * Instantiate handler for process of docker response for list of libraries.
+     *
+     * @param selfService REST pointer for Self Service.
+     * @param action      docker action.
+     * @param uuid        request UID.
+     * @param user        the name of user.
+     * @param group       the name of a group.
+     */
+    @JsonCreator
+    public LibListCallbackHandler(
+            @JacksonInject RESTService selfService, @JsonProperty("action") DockerAction action,
+            @JsonProperty("uuid") String uuid, @JsonProperty("user") String user,
+            @JsonProperty("group") String group) {
+        super(selfService, user, uuid, action);
+        this.group = group;
+    }
+
+    @Override
+    protected String getCallbackURI() {
+        return ApiCallbacks.UPDATE_LIBS_URI;
+    }
+
+    @Override
+    protected LibListStatusDTO parseOutResponse(JsonNode resultNode, LibListStatusDTO status) {
+        if (UserInstanceStatus.FAILED == UserInstanceStatus.of(status.getStatus())) {
+            return status;
+        }
+        if (resultNode == null) {
+            throw new DatalabException("Can't handle response result node is null");
+        }
+
+        JsonNode resultFileNode = resultNode.get(FILE);
+        if (resultFileNode == null) {
+            throw new DatalabException("Can't handle response without property " + FILE);
+        }
+
+        Path path = Paths.get(resultFileNode.asText()).toAbsolutePath();
+        if (path.toFile().exists()) {
+            try {
+                status.withLibs(new String(Files.readAllBytes(path)));
+                Files.delete(path);
+                return status;
+            } catch (IOException e) {
+                throw new DatalabException("Can't read file " + path + " : " + e.getLocalizedMessage(), e);
+            }
+        } else {
+            throw new DatalabException("Can't handle response. The file " + path + " does not exist");
+        }
+    }
+
+    @Override
+    protected LibListStatusDTO getBaseStatusDTO(UserInstanceStatus status) {
+        return super.getBaseStatusDTO(status)
+                .withGroup(group);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/PersistentFileHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/PersistentFileHandler.java
new file mode 100644
index 0000000..f7f9625
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/PersistentFileHandler.java
@@ -0,0 +1,51 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public final class PersistentFileHandler {
+
+    private final FileHandlerCallback handler;
+    private final long timeout;
+    private final String directory;
+
+    @JsonCreator
+    public PersistentFileHandler(@JsonProperty("handler") FileHandlerCallback handler, @JsonProperty("timeout")
+            long timeout, @JsonProperty("directory") String directory) {
+        this.handler = handler;
+        this.timeout = timeout;
+        this.directory = directory;
+    }
+
+    public FileHandlerCallback getHandler() {
+        return handler;
+    }
+
+    public long getTimeout() {
+        return timeout;
+    }
+
+    public String getDirectory() {
+        return directory;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ProjectCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ProjectCallbackHandler.java
new file mode 100644
index 0000000..738a2fc
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ProjectCallbackHandler.java
@@ -0,0 +1,71 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import com.epam.datalab.dto.base.project.ProjectResult;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.io.IOException;
+
+public class ProjectCallbackHandler extends ResourceCallbackHandler<ProjectResult> {
+
+
+    private final String callbackUri;
+    private final String projectName;
+    private final Class<? extends EdgeInfo> clazz;
+    private final String endpointName;
+
+    public ProjectCallbackHandler(RESTService selfService, String user,
+                                  String uuid, DockerAction action, String callbackUri, String projectName,
+                                  Class<? extends EdgeInfo> clazz, String endpointName) {
+        super(selfService, user, uuid, action);
+        this.callbackUri = callbackUri;
+        this.projectName = projectName;
+        this.clazz = clazz;
+        this.endpointName = endpointName;
+    }
+
+    @Override
+    protected String getCallbackURI() {
+        return callbackUri;
+    }
+
+    @Override
+    protected ProjectResult parseOutResponse(JsonNode resultNode, ProjectResult baseStatus) {
+        baseStatus.setProjectName(projectName);
+        baseStatus.setEndpointName(endpointName);
+        if (resultNode != null && getAction() == DockerAction.CREATE
+                && UserInstanceStatus.of(baseStatus.getStatus()) != UserInstanceStatus.FAILED) {
+            try {
+                final EdgeInfo projectEdgeInfo = mapper.readValue(resultNode.toString(), clazz);
+                baseStatus.setEdgeInfo(projectEdgeInfo);
+            } catch (IOException e) {
+                throw new DatalabException("Cannot parse the EDGE info in JSON: " + e.getLocalizedMessage(), e);
+            }
+        }
+
+        return baseStatus;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ResourceCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ResourceCallbackHandler.java
new file mode 100644
index 0000000..623ca4f
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ResourceCallbackHandler.java
@@ -0,0 +1,210 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.dto.StatusBaseDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.ParameterizedType;
+import java.time.Instant;
+import java.util.Date;
+
+public abstract class ResourceCallbackHandler<T extends StatusBaseDTO<?>> implements FileHandlerCallback {
+    private static final Logger log = LoggerFactory.getLogger(ResourceCallbackHandler.class);
+    final ObjectMapper mapper = new ObjectMapper().configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
+
+    private static final String STATUS_FIELD = "status";
+    protected static final String RESPONSE_NODE = "response";
+    protected static final String RESULT_NODE = "result";
+    private static final String ERROR_NODE = "error";
+
+    private static final String OK_STATUS = "ok";
+
+    @JsonIgnore
+    private final RESTService selfService;
+    @JsonProperty
+    private final String user;
+    @JsonProperty
+    private final String uuid;
+    @JsonProperty
+    private final DockerAction action;
+    @JsonProperty
+    private final Class<T> resultType;
+
+    @SuppressWarnings("unchecked")
+    public ResourceCallbackHandler(RESTService selfService, String user,
+                                   String uuid, DockerAction action) {
+        this.selfService = selfService;
+        this.user = user;
+        this.uuid = uuid;
+        this.action = action;
+        this.resultType =
+                (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
+    }
+
+    public ResourceCallbackHandler(RESTService selfService, String user,
+                                   String uuid,
+                                   DockerAction action,
+                                   Class<T> resultType) {
+        this.selfService = selfService;
+        this.user = user;
+        this.uuid = uuid;
+        this.action = action;
+        this.resultType = resultType;
+    }
+
+    @Override
+    public String getUUID() {
+        return uuid;
+    }
+
+    @Override
+    public boolean checkUUID(String uuid) {
+        return this.uuid.equals(uuid);
+    }
+
+    @Override
+    public String getUser() {
+        return user;
+    }
+
+    public DockerAction getAction() {
+        return action;
+    }
+
+    private void selfServicePost(T object) {
+        debugMessage("Send post request to self service {} for UUID {}, object is {}",
+                getCallbackURI(), uuid, object);
+        try {
+            selfService.post(getCallbackURI(), object, resultType);
+        } catch (Exception e) {
+            log.error("Send request or response error for UUID {}: {}", uuid, e.getLocalizedMessage(), e);
+            throw new DatalabException("Send request or responce error for UUID " + uuid + ": " + e.getLocalizedMessage()
+                    , e);
+        }
+    }
+
+    @Override
+    public boolean handle(String fileName, byte[] content) throws Exception {
+        debugMessage("Got file {} while waiting for UUID {}, for action {}, docker response: {}",
+                fileName, uuid, action.name(), new String(content));
+        JsonNode document = mapper.readTree(content);
+        boolean success = isSuccess(document);
+        UserInstanceStatus status = calcStatus(action, success);
+        T result = getBaseStatusDTO(status);
+
+        JsonNode resultNode = document.get(RESPONSE_NODE).get(RESULT_NODE);
+        if (success) {
+            debugMessage("Did {} resource for user: {}, UUID: {}", action, user, uuid);
+        } else {
+            log.error("Could not {} resource for user: {}, UUID: {}", action, user, uuid);
+            result.setErrorMessage(getTextValue(resultNode.get(ERROR_NODE)));
+        }
+        result = parseOutResponse(resultNode, result);
+
+        selfServicePost(result);
+        return !UserInstanceStatus.FAILED.equals(status);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void handleError(String errorMessage) {
+        try {
+            selfServicePost((T) getBaseStatusDTO(UserInstanceStatus.FAILED)
+                    .withErrorMessage(errorMessage));
+        } catch (Exception t) {
+            throw new DatalabException("Could not send error message to Self Service for UUID " + uuid + ", user " + user + ": " + errorMessage, t);
+        }
+    }
+
+    protected abstract String getCallbackURI();
+
+    protected abstract T parseOutResponse(JsonNode document, T baseStatus);
+
+    @SuppressWarnings("unchecked")
+    protected T getBaseStatusDTO(UserInstanceStatus status) {
+        try {
+            return (T) resultType.newInstance()
+                    .withRequestId(uuid)
+                    .withUser(user)
+                    .withStatus(status)
+                    .withUptime(getUptime(status));
+        } catch (Exception t) {
+            throw new DatalabException("Something went wrong", t);
+        }
+    }
+
+    private boolean isSuccess(JsonNode document) {
+        return OK_STATUS.equals(document.get(STATUS_FIELD).textValue());
+    }
+
+    private UserInstanceStatus calcStatus(DockerAction action, boolean success) {
+        if (success) {
+            switch (action) {
+                case STATUS:
+                case GIT_CREDS:
+                case LIB_LIST:
+                case LIB_INSTALL:
+                case CREATE_IMAGE:
+                    return UserInstanceStatus.CREATED; // Any status besides failed
+                case CREATE:
+                case CONFIGURE:
+                case START:
+                case RECONFIGURE_SPARK:
+                    return UserInstanceStatus.RUNNING;
+                case STOP:
+                    return UserInstanceStatus.STOPPED;
+                case TERMINATE:
+                    return UserInstanceStatus.TERMINATED;
+                default:
+                    break;
+            }
+        }
+        return UserInstanceStatus.FAILED;
+    }
+
+    protected Date getUptime(UserInstanceStatus status) {
+        return UserInstanceStatus.RUNNING == status ? Date.from(Instant.now()) : null;
+    }
+
+    protected String getTextValue(JsonNode jsonNode) {
+        return jsonNode != null ? jsonNode.textValue() : null;
+    }
+
+    private void debugMessage(String format, Object... arguments) {
+        if (action == DockerAction.STATUS) {
+            log.trace(format, arguments);
+        } else {
+            log.debug(format, arguments);
+        }
+    }
+
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ResourcesStatusCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ResourcesStatusCallbackHandler.java
new file mode 100644
index 0000000..53e8d8a
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ResourcesStatusCallbackHandler.java
@@ -0,0 +1,93 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.dto.status.EnvResourceList;
+import com.epam.datalab.dto.status.EnvStatusDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.fasterxml.jackson.annotation.JacksonInject;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Date;
+
+import static com.epam.datalab.rest.contracts.ApiCallbacks.INFRASTRUCTURE;
+import static com.epam.datalab.rest.contracts.ApiCallbacks.STATUS_URI;
+
+@Slf4j
+public class ResourcesStatusCallbackHandler extends ResourceCallbackHandler<EnvStatusDTO> {
+
+    @JsonCreator
+    public ResourcesStatusCallbackHandler(
+            @JacksonInject RESTService selfService, @JsonProperty("action") DockerAction
+            action, @JsonProperty("uuid") String uuid, @JsonProperty("user") String user) {
+        super(selfService, user, uuid, action);
+    }
+
+    @Override
+    protected String getCallbackURI() {
+        return INFRASTRUCTURE + STATUS_URI;
+    }
+
+    @Override
+    protected EnvStatusDTO parseOutResponse(JsonNode resultNode, EnvStatusDTO baseStatus) {
+        if (resultNode == null) {
+            return baseStatus;
+        }
+
+        EnvResourceList resourceList;
+        try {
+            resourceList = mapper.readValue(resultNode.toString(), EnvResourceList.class);
+        } catch (IOException e) {
+            throw new DatalabException("Docker response for UUID " + getUUID() + " not valid: " + e.getLocalizedMessage()
+                    , e);
+        }
+
+        baseStatus.withResourceList(resourceList)
+                .withUptime(Date.from(Instant.now()));
+
+        log.trace("Inner status {}", baseStatus);
+
+        return baseStatus;
+    }
+
+    @Override
+    public boolean handle(String fileName, byte[] content) throws Exception {
+        try {
+            return super.handle(fileName, content);
+        } catch (Exception e) {
+            log.warn("Could not retrive the status of resources for UUID {} and user {}: {}",
+                    getUUID(), getUser(), e.getLocalizedMessage(), e);
+        }
+        return true; // Always necessary return true for status response
+    }
+
+    @Override
+    public void handleError(String errorMessage) {
+        // Nothing action for status response
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ReuploadKeyCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ReuploadKeyCallbackHandler.java
new file mode 100644
index 0000000..ceb67a1
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ReuploadKeyCallbackHandler.java
@@ -0,0 +1,124 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers;
+
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyCallbackDTO;
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyStatus;
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyStatusDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.fasterxml.jackson.annotation.JacksonInject;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.core.Response;
+
+@Slf4j
+public class ReuploadKeyCallbackHandler implements FileHandlerCallback {
+    private static final ObjectMapper MAPPER = new ObjectMapper()
+            .configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
+    private static final String STATUS_FIELD = "status";
+    private static final String ERROR_MESSAGE_FIELD = "error_message";
+    @JsonProperty
+    private final String uuid;
+    @JsonProperty
+    private final ReuploadKeyCallbackDTO dto;
+    private final RESTService selfService;
+    @JsonProperty
+    private final String callbackUrl;
+    @JsonProperty
+    private final String user;
+
+    @JsonCreator
+    public ReuploadKeyCallbackHandler(@JacksonInject RESTService selfService,
+                                      @JsonProperty("callbackUrl") String callbackUrl,
+                                      @JsonProperty("user") String user,
+                                      @JsonProperty("dto") ReuploadKeyCallbackDTO dto) {
+        this.selfService = selfService;
+        this.uuid = dto.getId();
+        this.callbackUrl = callbackUrl;
+        this.user = user;
+        this.dto = dto;
+    }
+
+    @Override
+    public String getUUID() {
+        return uuid;
+    }
+
+    @Override
+    public boolean checkUUID(String uuid) {
+        return this.uuid.equals(uuid);
+    }
+
+    @Override
+    public boolean handle(String fileName, byte[] content) throws Exception {
+        final String fileContent = new String(content);
+        log.debug("Got file {} while waiting for UUID {}, reupload key response: {}", fileName, uuid, fileContent);
+
+        final JsonNode jsonNode = MAPPER.readTree(fileContent);
+        final String status = jsonNode.get(STATUS_FIELD).textValue();
+        ReuploadKeyStatusDTO reuploadKeyStatusDTO;
+        if ("ok".equals(status)) {
+            reuploadKeyStatusDTO = buildReuploadKeyStatusDto(ReuploadKeyStatus.COMPLETED);
+        } else {
+            reuploadKeyStatusDTO = buildReuploadKeyStatusDto(ReuploadKeyStatus.FAILED)
+                    .withErrorMessage(jsonNode.get(ERROR_MESSAGE_FIELD).textValue());
+        }
+        selfServicePost(reuploadKeyStatusDTO);
+        return "ok".equals(status);
+    }
+
+    private void selfServicePost(ReuploadKeyStatusDTO statusDTO) {
+        log.debug("Send post request to self service for UUID {}, object is {}", uuid, statusDTO);
+        try {
+            selfService.post(callbackUrl, statusDTO, Response.class);
+        } catch (Exception e) {
+            log.error("Send request or response error for UUID {}: {}", uuid, e.getLocalizedMessage(), e);
+            throw new DatalabException("Send request or response error for UUID " + uuid + ": "
+                    + e.getLocalizedMessage(), e);
+        }
+    }
+
+    @Override
+    public void handleError(String errorMessage) {
+        buildReuploadKeyStatusDto(ReuploadKeyStatus.FAILED)
+                .withErrorMessage(errorMessage);
+    }
+
+    @Override
+    public String getUser() {
+        return user;
+    }
+
+    private ReuploadKeyStatusDTO buildReuploadKeyStatusDto(ReuploadKeyStatus status) {
+        return new ReuploadKeyStatusDTO()
+                .withRequestId(uuid)
+                .withReuploadKeyCallbackDto(dto)
+                .withReuploadKeyStatus(status)
+                .withUser(user);
+    }
+
+}
+
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/dao/CallbackHandlerDao.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/dao/CallbackHandlerDao.java
new file mode 100644
index 0000000..ba8144a
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/dao/CallbackHandlerDao.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.datalab.backendapi.core.response.handlers.dao;
+
+import com.epam.datalab.backendapi.core.response.handlers.PersistentFileHandler;
+
+import java.util.List;
+
+public interface CallbackHandlerDao {
+
+    void upsert(PersistentFileHandler handlerCallback);
+
+    List<PersistentFileHandler> findAll();
+
+    void remove(String handlerId);
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/dao/FileSystemCallbackHandlerDao.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/dao/FileSystemCallbackHandlerDao.java
new file mode 100644
index 0000000..6e39555
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/dao/FileSystemCallbackHandlerDao.java
@@ -0,0 +1,121 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers.dao;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.response.handlers.PersistentFileHandler;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.util.FileUtils;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import static java.util.stream.Collectors.toList;
+
+@Singleton
+@Slf4j
+public class FileSystemCallbackHandlerDao implements CallbackHandlerDao {
+
+    @Inject
+    private ProvisioningServiceApplicationConfiguration configuration;
+    @Inject
+    private ObjectMapper mapper;
+
+    @Override
+    public void upsert(PersistentFileHandler handlerCallback) {
+        removeWithUUID(handlerCallback.getHandler().getUUID());
+        final String fileName = fileName(handlerCallback.getHandler().getId());
+        final String absolutePath = getAbsolutePath(fileName);
+        saveToFile(handlerCallback, fileName, absolutePath);
+    }
+
+    @Override
+    public List<PersistentFileHandler> findAll() {
+        try (final Stream<Path> pathStream = Files.list(Paths.get(configuration.getHandlerDirectory()))) {
+            return pathStream.map(this::toPersistentFileHandler)
+                    .filter(Optional::isPresent)
+                    .map(Optional::get)
+                    .collect(toList());
+        } catch (IOException e) {
+            log.error("Can not restore handlers due to: {}", e.getMessage(), e);
+        }
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void remove(String handlerId) {
+        try {
+            Files.delete(Paths.get(getAbsolutePath(fileName(handlerId))));
+        } catch (Exception e) {
+            log.error("Can not remove handler {} due to: {}", handlerId, e.getMessage(), e);
+            throw new DatalabException("Can not remove handler " + handlerId + " due to: " + e.getMessage());
+        }
+    }
+
+    private void removeWithUUID(String uuid) {
+        try (final Stream<Path> pathStream = Files.list(Paths.get(configuration.getHandlerDirectory()))) {
+            pathStream.map(Path::toString)
+                    .filter(path -> path.contains(uuid))
+                    .findAny()
+                    .ifPresent(FileUtils::deleteFile);
+        } catch (IOException e) {
+            log.error("Problem occurred with accessing directory {} due to: {}", configuration.getHandlerDirectory(),
+                    e.getLocalizedMessage(), e);
+        }
+    }
+
+    private String getAbsolutePath(String fileName) {
+        return configuration.getHandlerDirectory() + File.separator + fileName;
+    }
+
+    private void saveToFile(PersistentFileHandler handlerCallback, String fileName, String absolutePath) {
+        try {
+            log.trace("Persisting callback handler to file {}", absolutePath);
+            Files.write(Paths.get(absolutePath), mapper.writeValueAsBytes(handlerCallback), StandardOpenOption.CREATE);
+        } catch (Exception e) {
+            log.warn("Can not persist file handler {} due to {}", fileName, e.getMessage(), e);
+        }
+    }
+
+    private String fileName(String handlerId) {
+        return handlerId + ".json";
+    }
+
+    private Optional<PersistentFileHandler> toPersistentFileHandler(Path path) {
+        try {
+            return Optional.of(mapper.readValue(path.toFile(), PersistentFileHandler.class));
+        } catch (Exception e) {
+            log.warn("Can not deserialize file handler from file: {}", path.toString(), e);
+        }
+        return Optional.empty();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/AwsProvisioningModule.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/AwsProvisioningModule.java
new file mode 100644
index 0000000..bced6b7
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/AwsProvisioningModule.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.datalab.backendapi.modules;
+
+import com.epam.datalab.backendapi.resources.aws.ComputationalResourceAws;
+import com.epam.datalab.backendapi.resources.aws.EdgeResourceAws;
+import com.epam.datalab.backendapi.resources.aws.ExploratoryResourceAws;
+import com.epam.datalab.backendapi.resources.aws.InfrastructureResourceAws;
+import com.epam.datalab.cloud.CloudModule;
+import com.google.inject.Injector;
+import io.dropwizard.setup.Environment;
+
+public class AwsProvisioningModule extends CloudModule {
+
+    @Override
+    public void init(Environment environment, Injector injector) {
+        environment.jersey().register(injector.getInstance(EdgeResourceAws.class));
+        environment.jersey().register(injector.getInstance(InfrastructureResourceAws.class));
+        environment.jersey().register(injector.getInstance(ExploratoryResourceAws.class));
+        environment.jersey().register(injector.getInstance(ComputationalResourceAws.class));
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/AzureProvisioningModule.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/AzureProvisioningModule.java
new file mode 100644
index 0000000..b0f2555
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/AzureProvisioningModule.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.datalab.backendapi.modules;
+
+import com.epam.datalab.backendapi.resources.azure.ComputationalResourceAzure;
+import com.epam.datalab.backendapi.resources.azure.EdgeResourceAzure;
+import com.epam.datalab.backendapi.resources.azure.ExploratoryResourceAzure;
+import com.epam.datalab.backendapi.resources.azure.InfrastructureResourceAzure;
+import com.epam.datalab.cloud.CloudModule;
+import com.google.inject.Injector;
+import io.dropwizard.setup.Environment;
+
+public class AzureProvisioningModule extends CloudModule {
+
+    @Override
+    public void init(Environment environment, Injector injector) {
+        environment.jersey().register(injector.getInstance(EdgeResourceAzure.class));
+        environment.jersey().register(injector.getInstance(InfrastructureResourceAzure.class));
+        environment.jersey().register(injector.getInstance(ExploratoryResourceAzure.class));
+        environment.jersey().register(injector.getInstance(ComputationalResourceAzure.class));
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/CloudModuleConfigurator.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/CloudModuleConfigurator.java
new file mode 100644
index 0000000..ba1595b
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/CloudModuleConfigurator.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.backendapi.modules;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.cloud.CloudModule;
+
+public class CloudModuleConfigurator {
+
+    private CloudModuleConfigurator() {
+    }
+
+    public static CloudModule getCloudModule(ProvisioningServiceApplicationConfiguration configuration) {
+        switch (configuration.getCloudProvider()) {
+            case AWS:
+                return new AwsProvisioningModule();
+            case AZURE:
+                return new AzureProvisioningModule();
+            case GCP:
+                return new GcpProvisioningModule();
+            default:
+                throw new UnsupportedOperationException("Unsupported cloud provider " + configuration.getCloudProvider());
+        }
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/GcpProvisioningModule.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/GcpProvisioningModule.java
new file mode 100644
index 0000000..2e07e39
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/GcpProvisioningModule.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.datalab.backendapi.modules;
+
+import com.epam.datalab.backendapi.resources.gcp.ComputationalResourceGcp;
+import com.epam.datalab.backendapi.resources.gcp.EdgeResourceGcp;
+import com.epam.datalab.backendapi.resources.gcp.ExploratoryResourceGcp;
+import com.epam.datalab.backendapi.resources.gcp.InfrastructureResourceGcp;
+import com.epam.datalab.cloud.CloudModule;
+import com.google.inject.Injector;
+import io.dropwizard.setup.Environment;
+
+public class GcpProvisioningModule extends CloudModule {
+
+    @Override
+    public void init(Environment environment, Injector injector) {
+        environment.jersey().register(injector.getInstance(EdgeResourceGcp.class));
+        environment.jersey().register(injector.getInstance(InfrastructureResourceGcp.class));
+        environment.jersey().register(injector.getInstance(ExploratoryResourceGcp.class));
+        environment.jersey().register(injector.getInstance(ComputationalResourceGcp.class));
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/ModuleFactory.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/ModuleFactory.java
new file mode 100644
index 0000000..e55ee25
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/ModuleFactory.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.backendapi.modules;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.google.inject.AbstractModule;
+import io.dropwizard.setup.Environment;
+
+public class ModuleFactory {
+
+    private ModuleFactory() {
+    }
+
+    /**
+     * Instantiates an application configuration of Provisioning Service for production or tests if
+     * the mock property of configuration is set to <b>true</b> and method {@link ProvisioningServiceApplicationConfiguration#isDevMode()}}
+     * returns <b>true</b> value.
+     *
+     * @param configuration application configuration of Provisioning Service.
+     * @param environment   environment of Provisioning Service.
+     */
+    public static AbstractModule getModule(ProvisioningServiceApplicationConfiguration configuration, Environment environment) {
+        return configuration.isDevMode()
+                ? new ProvisioningDevModule(configuration, environment)
+                : new ProductionModule(configuration, environment);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/ProductionModule.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/ProductionModule.java
new file mode 100644
index 0000000..f885338
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/ProductionModule.java
@@ -0,0 +1,89 @@
+/*
+ * 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.datalab.backendapi.modules;
+
+import com.epam.datalab.ModuleBase;
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.DockerWarmuper;
+import com.epam.datalab.backendapi.core.MetadataHolder;
+import com.epam.datalab.backendapi.core.commands.CommandExecutor;
+import com.epam.datalab.backendapi.core.commands.ICommandExecutor;
+import com.epam.datalab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
+import com.epam.datalab.backendapi.core.response.handlers.dao.FileSystemCallbackHandlerDao;
+import com.epam.datalab.backendapi.service.BucketService;
+import com.epam.datalab.backendapi.service.CheckInactivityService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.service.RestoreCallbackHandlerService;
+import com.epam.datalab.backendapi.service.impl.CheckInactivityServiceImpl;
+import com.epam.datalab.backendapi.service.impl.ProjectServiceImpl;
+import com.epam.datalab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
+import com.epam.datalab.backendapi.service.impl.aws.BucketServiceAwsImpl;
+import com.epam.datalab.backendapi.service.impl.azure.BucketServiceAzureImpl;
+import com.epam.datalab.backendapi.service.impl.gcp.BucketServiceGcpImpl;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.rest.client.RESTService;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.name.Names;
+import io.dropwizard.setup.Environment;
+
+/**
+ * Production class for an application configuration of SelfService.
+ */
+public class ProductionModule extends ModuleBase<ProvisioningServiceApplicationConfiguration> {
+
+    /**
+     * Instantiates an application configuration of SelfService for production environment.
+     *
+     * @param configuration application configuration of SelfService.
+     * @param environment   environment of SelfService.
+     */
+    ProductionModule(ProvisioningServiceApplicationConfiguration configuration, Environment environment) {
+        super(configuration, environment);
+    }
+
+    @Override
+    protected void configure() {
+        bind(ProvisioningServiceApplicationConfiguration.class).toInstance(configuration);
+
+        bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.SECURITY_SERVICE_NAME))
+                .toInstance(configuration.getSecurityFactory()
+                        .build(environment, ServiceConsts.SECURITY_SERVICE_NAME, ServiceConsts
+                                .PROVISIONING_USER_AGENT));
+
+        bind(RESTService.class).toInstance(configuration.getSelfFactory().build(environment, ServiceConsts
+                .SELF_SERVICE_NAME));
+        bind(MetadataHolder.class).to(DockerWarmuper.class);
+        bind(ICommandExecutor.class).to(CommandExecutor.class).asEagerSingleton();
+        bind(ObjectMapper.class).toInstance(new ObjectMapper().configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true));
+        bind(CallbackHandlerDao.class).to(FileSystemCallbackHandlerDao.class);
+        bind(RestoreCallbackHandlerService.class).to(RestoreCallbackHandlerServiceImpl.class);
+        bind(CheckInactivityService.class).to(CheckInactivityServiceImpl.class);
+        bind(ProjectService.class).to(ProjectServiceImpl.class);
+        if (configuration.getCloudProvider() == CloudProvider.GCP) {
+            bind(BucketService.class).to(BucketServiceGcpImpl.class);
+        } else if (configuration.getCloudProvider() == CloudProvider.AWS) {
+            bind(BucketService.class).to(BucketServiceAwsImpl.class);
+        } else if (configuration.getCloudProvider() == CloudProvider.AZURE) {
+            bind(BucketService.class).to(BucketServiceAzureImpl.class);
+        }
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/ProvisioningDevModule.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/ProvisioningDevModule.java
new file mode 100644
index 0000000..a94e706
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/modules/ProvisioningDevModule.java
@@ -0,0 +1,148 @@
+/*
+ * 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.datalab.backendapi.modules;
+
+import com.epam.datalab.ModuleBase;
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.auth.contract.SecurityAPI;
+import com.epam.datalab.auth.dto.UserCredentialDTO;
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.DockerWarmuper;
+import com.epam.datalab.backendapi.core.MetadataHolder;
+import com.epam.datalab.backendapi.core.commands.CommandExecutorMock;
+import com.epam.datalab.backendapi.core.commands.ICommandExecutor;
+import com.epam.datalab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
+import com.epam.datalab.backendapi.core.response.handlers.dao.FileSystemCallbackHandlerDao;
+import com.epam.datalab.backendapi.service.BucketService;
+import com.epam.datalab.backendapi.service.CheckInactivityService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.service.RestoreCallbackHandlerService;
+import com.epam.datalab.backendapi.service.impl.CheckInactivityServiceImpl;
+import com.epam.datalab.backendapi.service.impl.ProjectServiceImpl;
+import com.epam.datalab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
+import com.epam.datalab.backendapi.service.impl.aws.BucketServiceAwsImpl;
+import com.epam.datalab.backendapi.service.impl.azure.BucketServiceAzureImpl;
+import com.epam.datalab.backendapi.service.impl.gcp.BucketServiceGcpImpl;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.DockerAPI;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.name.Names;
+import io.dropwizard.setup.Environment;
+
+import javax.ws.rs.core.Response;
+
+/**
+ * Mock class for an application configuration of Provisioning Service for tests.
+ */
+public class ProvisioningDevModule extends ModuleBase<ProvisioningServiceApplicationConfiguration> implements
+        SecurityAPI, DockerAPI {
+
+    private static final String TOKEN = "token123";
+    private static final String OPERATION_IS_NOT_SUPPORTED = "Operation is not supported";
+
+    /**
+     * Instantiates an application configuration of Provisioning Service for tests.
+     *
+     * @param configuration application configuration of Provisioning Service.
+     * @param environment   environment of Provisioning Service.
+     */
+    ProvisioningDevModule(ProvisioningServiceApplicationConfiguration configuration, Environment environment) {
+        super(configuration, environment);
+    }
+
+    @Override
+    protected void configure() {
+        bind(ProvisioningServiceApplicationConfiguration.class).toInstance(configuration);
+        bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.SECURITY_SERVICE_NAME)).toInstance
+                (createAuthenticationService());
+        bind(RESTService.class).toInstance(configuration.getSelfFactory().build(environment, ServiceConsts
+                .SELF_SERVICE_NAME));
+        bind(MetadataHolder.class).to(DockerWarmuper.class);
+        bind(ICommandExecutor.class).toInstance(new CommandExecutorMock(configuration.getCloudProvider()));
+        bind(ObjectMapper.class).toInstance(new ObjectMapper().configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true));
+        bind(CallbackHandlerDao.class).to(FileSystemCallbackHandlerDao.class);
+        bind(RestoreCallbackHandlerService.class).to(RestoreCallbackHandlerServiceImpl.class);
+        bind(CheckInactivityService.class).to(CheckInactivityServiceImpl.class);
+        bind(ProjectService.class).to(ProjectServiceImpl.class);
+        if (configuration.getCloudProvider() == CloudProvider.GCP) {
+            bind(BucketService.class).to(BucketServiceGcpImpl.class);
+        } else if (configuration.getCloudProvider() == CloudProvider.AWS) {
+            bind(BucketService.class).to(BucketServiceAwsImpl.class);
+        } else if (configuration.getCloudProvider() == CloudProvider.AZURE) {
+            bind(BucketService.class).to(BucketServiceAzureImpl.class);
+        }
+    }
+
+    /**
+     * Creates and returns the mock object for authentication service.
+     */
+    @SuppressWarnings("unchecked")
+    private RESTService createAuthenticationService() {
+        return new RESTService() {
+            @Override
+            public <T> T post(String path, Object parameter, Class<T> clazz) {
+                if (LOGIN.equals(path)) {
+                    return authorize((UserCredentialDTO) parameter);
+                } else if (GET_USER_INFO.equals(path) && TOKEN.equals(parameter) && clazz.equals(UserInfo.class)) {
+                    return (T) getUserInfo();
+                }
+                throw new UnsupportedOperationException(OPERATION_IS_NOT_SUPPORTED);
+            }
+
+            private <T> T authorize(UserCredentialDTO credential) {
+                if ("test".equals(credential.getUsername())) {
+                    return (T) Response.ok(TOKEN).build();
+                } else {
+                    return (T) Response.status(Response.Status.UNAUTHORIZED)
+                            .entity("Username or password is invalid")
+                            .build();
+                }
+            }
+
+            @Override
+            public <T> T get(String path, Class<T> clazz) {
+                throw new UnsupportedOperationException(OPERATION_IS_NOT_SUPPORTED);
+            }
+
+            @Override
+            public <T> T get(String path, String accessToken, Class<T> clazz) {
+                throw new UnsupportedOperationException(OPERATION_IS_NOT_SUPPORTED);
+            }
+
+            @Override
+            public <T> T post(String path, String accessToken, Object parameter, Class<T> clazz) {
+                throw new UnsupportedOperationException(OPERATION_IS_NOT_SUPPORTED);
+            }
+        };
+    }
+
+    /**
+     * Create and return UserInfo object.
+     */
+    private UserInfo getUserInfo() {
+        UserInfo userInfo = new UserInfo("test", TOKEN);
+        userInfo.addRole("test");
+        userInfo.addRole("dev");
+        return userInfo;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/BackupResource.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/BackupResource.java
new file mode 100644
index 0000000..4b0cce7
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/BackupResource.java
@@ -0,0 +1,76 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.commands.ICommandExecutor;
+import com.epam.datalab.backendapi.core.commands.PythonBackupCommand;
+import com.epam.datalab.backendapi.core.response.folderlistener.FolderListenerExecutor;
+import com.epam.datalab.backendapi.core.response.handlers.BackupCallbackHandler;
+import com.epam.datalab.dto.backup.EnvBackupDTO;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.epam.datalab.rest.contracts.BackupAPI;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+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;
+
+@Path(BackupAPI.BACKUP)
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class BackupResource {
+
+    @Inject
+    private ProvisioningServiceApplicationConfiguration configuration;
+    @Inject
+    protected FolderListenerExecutor folderListenerExecutor;
+    @Inject
+    protected ICommandExecutor commandExecutor;
+    @Inject
+    protected RESTService selfService;
+
+
+    @POST
+    public Response createBackup(@Auth UserInfo ui, EnvBackupDTO dto) {
+        folderListenerExecutor.start(configuration.getBackupDirectory(), configuration.getProcessTimeout(),
+                new BackupCallbackHandler(selfService, ApiCallbacks.BACKUP_URI, ui.getName(), dto));
+        String command = new PythonBackupCommand(configuration.getBackupScriptPath())
+                .withConfig(dto.getConfigFiles())
+                .withJars(dto.getJars())
+                .withKeys(dto.getKeys())
+                .withDBBackup(dto.isDatabaseBackup())
+                .withLogsBackup(dto.isLogsBackup())
+                .withResponsePath(configuration.getBackupDirectory())
+                .withRequestId(dto.getId())
+                .withSystemUser()
+                .withCertificates(dto.getCertificates()).toCMD();
+        commandExecutor.executeAsync(ui.getName(), dto.getId(), command);
+        return Response.accepted(dto.getId()).build();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/BucketResource.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/BucketResource.java
new file mode 100644
index 0000000..71716b0
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/BucketResource.java
@@ -0,0 +1,144 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.BucketService;
+import com.epam.datalab.dto.bucket.BucketDeleteDTO;
+import com.epam.datalab.dto.bucket.FolderUploadDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.fileupload.FileItemIterator;
+import org.apache.commons.fileupload.FileItemStream;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.commons.fileupload.util.Streams;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+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.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+
+@Slf4j
+@Path("/bucket")
+public class BucketResource {
+    private static final String OBJECT_FORM_FIELD = "object";
+    private static final String BUCKET_FORM_FIELD = "bucket";
+    private static final String SIZE_FORM_FIELD = "file-size";
+
+    private final BucketService bucketService;
+
+    @Inject
+    public BucketResource(BucketService bucketService) {
+        this.bucketService = bucketService;
+    }
+
+    @GET
+    @Path("/{bucket}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getListOfObjects(@Auth UserInfo userInfo,
+                                     @PathParam("bucket") String bucket) {
+        return Response.ok(bucketService.getObjects(bucket)).build();
+    }
+
+    @POST
+    @Path("/upload")
+    @Consumes(MediaType.MULTIPART_FORM_DATA)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response uploadObject(@Auth UserInfo userInfo, @Context HttpServletRequest request) {
+        upload(request);
+        return Response.ok().build();
+    }
+
+    @POST
+    @Path("/folder/upload")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response uploadFolder(@Auth UserInfo userInfo, @Valid FolderUploadDTO dto) {
+        bucketService.uploadFolder(userInfo, dto.getBucket(), dto.getFolder());
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/{bucket}/object/{object}/download")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_OCTET_STREAM)
+    public Response downloadObject(@Auth UserInfo userInfo, @Context HttpServletResponse resp,
+                                   @PathParam("object") String object,
+                                   @PathParam("bucket") String bucket) {
+        bucketService.downloadObject(bucket, object, resp);
+        return Response.ok().build();
+    }
+
+    @POST
+    @Path("/objects/delete")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response uploadObject(@Auth UserInfo userInfo, BucketDeleteDTO bucketDeleteDTO) {
+        bucketService.deleteObjects(bucketDeleteDTO.getBucket(), bucketDeleteDTO.getObjects());
+        return Response.ok().build();
+    }
+
+    private void upload(HttpServletRequest request) {
+        String object = null;
+        String bucket = null;
+        long fileSize = 0;
+
+        ServletFileUpload upload = new ServletFileUpload();
+        try {
+            FileItemIterator iterStream = upload.getItemIterator(request);
+            while (iterStream.hasNext()) {
+                FileItemStream item = iterStream.next();
+                try (InputStream stream = item.openStream()) {
+                    if (item.isFormField()) {
+                        if (OBJECT_FORM_FIELD.equals(item.getFieldName())) {
+                            object = Streams.asString(stream);
+                        }
+                        if (BUCKET_FORM_FIELD.equals(item.getFieldName())) {
+                            bucket = Streams.asString(stream);
+                        }
+                        if (SIZE_FORM_FIELD.equals(item.getFieldName())) {
+                            fileSize = Long.parseLong(Streams.asString(stream));
+                        }
+                    } else {
+                        bucketService.uploadObject(bucket, object, stream, item.getContentType(), fileSize);
+                    }
+                } catch (Exception e) {
+                    log.error("Cannot upload object {} to bucket {}. {}", object, bucket, e.getMessage(), e);
+                    throw new DatalabException(String.format("Cannot upload object %s to bucket %s. %s", object, bucket, e.getMessage()));
+                }
+            }
+        } catch (Exception e) {
+            log.error("Cannot upload object {} to bucket {}. {}", object, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot upload object %s to bucket %s. %s", object, bucket, e.getMessage()));
+        }
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/CallbackHandlerResource.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/CallbackHandlerResource.java
new file mode 100644
index 0000000..8062dd6
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/CallbackHandlerResource.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.backendapi.service.RestoreCallbackHandlerService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+
+@Path("/handler")
+@Slf4j
+public class CallbackHandlerResource {
+    private final RestoreCallbackHandlerService restoreCallbackHandlerService;
+
+    @Inject
+    public CallbackHandlerResource(RestoreCallbackHandlerService restoreCallbackHandlerService) {
+        this.restoreCallbackHandlerService = restoreCallbackHandlerService;
+    }
+
+    @POST
+    @Path("/restore")
+    public Response restoreHandlers() {
+        restoreCallbackHandlerService.restore();
+        return Response.ok().build();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/DockerResource.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/DockerResource.java
new file mode 100644
index 0000000..587bed6
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/DockerResource.java
@@ -0,0 +1,92 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.MetadataHolder;
+import com.epam.datalab.backendapi.core.commands.CommandBuilder;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.ICommandExecutor;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.dto.imagemetadata.ImageMetadataDTO;
+import com.epam.datalab.dto.imagemetadata.ImageType;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.util.Set;
+
+@Path("/docker")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class DockerResource implements DockerCommands {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DockerResource.class);
+
+    @Inject
+    private ProvisioningServiceApplicationConfiguration configuration;
+    @Inject
+    private MetadataHolder metadataHolder;
+    @Inject
+    private ICommandExecutor commandExecutor;
+    @Inject
+    private CommandBuilder commandBuilder;
+
+    @GET
+    @Path("{type}")
+    public Set<ImageMetadataDTO> getDockerImages(@Auth UserInfo ui, @PathParam("type") String type) {
+        LOGGER.debug("docker statuses asked for {}", type);
+        return metadataHolder
+                .getMetadata(ImageType.valueOf(type.toUpperCase()));
+    }
+
+    @Path("/run")
+    @POST
+    public String run(@Auth UserInfo ui, String image) {
+        LOGGER.debug("run docker image {}", image);
+        String uuid = DockerCommands.generateUUID();
+        commandExecutor.executeAsync(
+                ui.getName(),
+                uuid,
+                new RunDockerCommand()
+                        .withName(nameContainer("image", "runner"))
+                        .withVolumeForRootKeys(configuration.getKeyDirectory())
+                        .withVolumeForResponse(configuration.getImagesDirectory())
+                        .withRequestId(uuid)
+                        .withDryRun()
+                        .withActionRun(image)
+                        .toCMD()
+        );
+        return uuid;
+    }
+
+    public String getResourceType() {
+        return Directories.NOTEBOOK_LOG_DIRECTORY;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/GitExploratoryResource.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/GitExploratoryResource.java
new file mode 100644
index 0000000..aeedc24
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/GitExploratoryResource.java
@@ -0,0 +1,95 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.handlers.ExploratoryGitCredsCallbackHandler;
+import com.epam.datalab.backendapi.service.impl.DockerService;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.exploratory.ExploratoryBaseDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.util.Objects;
+
+@Path("/exploratory")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class GitExploratoryResource extends DockerService implements DockerCommands {
+
+    @Path("/git_creds")
+    @POST
+    public String gitCredsUpdate(@Auth UserInfo ui, ExploratoryGitCredsUpdateDTO dto) throws JsonProcessingException {
+        return action(ui.getName(), dto, DockerAction.GIT_CREDS);
+    }
+
+    private String action(String username, ExploratoryBaseDTO<?> dto, DockerAction action) throws JsonProcessingException {
+        log.debug("{} exploratory environment", action);
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallback(action, uuid, dto));
+
+        RunDockerCommand runDockerCommand = new RunDockerCommand()
+                .withInteractive()
+                .withName(nameContainer(dto.getEdgeUserName(), action, dto.getExploratoryName()))
+                .withVolumeForRootKeys(configuration.getKeyDirectory())
+                .withVolumeForResponse(configuration.getImagesDirectory())
+                .withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
+                .withResource(getResourceType())
+                .withRequestId(uuid)
+                .withConfKeyName(configuration.getAdminKey())
+                .withImage(dto.getNotebookImage())
+                .withAction(action);
+        if (configuration.getCloudProvider() == CloudProvider.AZURE &&
+                Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
+                !configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
+            runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
+        }
+
+        commandExecutor.executeAsync(username, uuid, commandBuilder.buildCommand(runDockerCommand, dto));
+        return uuid;
+    }
+
+    private FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, ExploratoryBaseDTO<?> dto) {
+        return new ExploratoryGitCredsCallbackHandler(selfService, action, uuid, dto.getCloudSettings().getIamUser(), dto.getExploratoryName());
+    }
+
+    private String nameContainer(String user, DockerAction action, String name) {
+        return nameContainer(user, action.toString(), "exploratory", name);
+    }
+
+    public String getResourceType() {
+        return Directories.NOTEBOOK_LOG_DIRECTORY;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ImageResource.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ImageResource.java
new file mode 100644
index 0000000..b565556
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ImageResource.java
@@ -0,0 +1,88 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.handlers.ImageCreateCallbackHandler;
+import com.epam.datalab.backendapi.service.impl.DockerService;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.exploratory.ExploratoryImageDTO;
+import com.epam.datalab.rest.contracts.ExploratoryAPI;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+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;
+import java.util.Objects;
+
+@Path(ExploratoryAPI.EXPLORATORY_IMAGE)
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ImageResource extends DockerService implements DockerCommands {
+
+    @POST
+    public Response createImage(@Auth UserInfo ui, ExploratoryImageDTO image) throws JsonProcessingException {
+        final String uuid = DockerCommands.generateUUID();
+
+        folderListenerExecutor.start(configuration.getImagesDirectory(), configuration.getResourceStatusPollTimeout(),
+                new ImageCreateCallbackHandler(selfService, uuid, DockerAction.CREATE_IMAGE, image));
+        String command = commandBuilder.buildCommand(getDockerCommand(DockerAction.CREATE_IMAGE, uuid, image), image);
+        commandExecutor.executeAsync(ui.getName(), uuid, command);
+        log.debug("Docker command: " + command);
+        return Response.accepted(uuid).build();
+    }
+
+
+    @Override
+    public String getResourceType() {
+        return Directories.NOTEBOOK_LOG_DIRECTORY;
+    }
+
+    private RunDockerCommand getDockerCommand(DockerAction action, String uuid, ExploratoryImageDTO image) {
+        RunDockerCommand runDockerCommand = new RunDockerCommand()
+                .withInteractive()
+                .withVolumeForRootKeys(configuration.getKeyDirectory())
+                .withVolumeForResponse(configuration.getImagesDirectory())
+                .withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
+                .withRequestId(uuid)
+                .withConfKeyName(configuration.getAdminKey())
+                .withAction(action)
+                .withResource(getResourceType())
+                .withImage(image.getNotebookImage())
+                .withName(nameContainer(image.getEdgeUserName(), action.toString(), image.getImageName()));
+        if (configuration.getCloudProvider() == CloudProvider.AZURE &&
+                Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
+                !configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
+            runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
+        }
+
+        return runDockerCommand;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/InfrastructureResource.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/InfrastructureResource.java
new file mode 100644
index 0000000..0b29fc6
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/InfrastructureResource.java
@@ -0,0 +1,65 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.CheckInactivityService;
+import com.epam.datalab.dto.computational.ComputationalCheckInactivityDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryCheckInactivityAction;
+import com.epam.datalab.rest.contracts.InfrasctructureAPI;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+
+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;
+
+@Path(InfrasctructureAPI.INFRASTRUCTURE)
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class InfrastructureResource {
+
+	@Inject
+	private CheckInactivityService checkInactivityService;
+
+	/**
+	 * Return status of provisioning service.
+	 */
+	@GET
+	public Response status(@Auth UserInfo ui) {
+		return Response.status(Response.Status.OK).build();
+	}
+
+	@POST
+	@Path("/exploratory/check_inactivity")
+	public String checkExploratoryInactivity(@Auth UserInfo ui, ExploratoryCheckInactivityAction dto) {
+		return checkInactivityService.checkExploratoryInactivity(ui.getName(), dto);
+	}
+
+	@POST
+	@Path("/computational/check_inactivity")
+	public String checkComputationalInactivity(@Auth UserInfo ui, ComputationalCheckInactivityDTO dto) {
+		return checkInactivityService.checkComputationalInactivity(ui.getName(), dto);
+	}
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/LibraryResource.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/LibraryResource.java
new file mode 100644
index 0000000..efe7ca2
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/LibraryResource.java
@@ -0,0 +1,195 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.handlers.LibInstallCallbackHandler;
+import com.epam.datalab.backendapi.core.response.handlers.LibListCallbackHandler;
+import com.epam.datalab.backendapi.service.impl.DockerService;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.LibListComputationalDTO;
+import com.epam.datalab.dto.LibListExploratoryDTO;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.exploratory.ExploratoryActionDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryBaseDTO;
+import com.epam.datalab.dto.exploratory.LibraryInstallDTO;
+import com.epam.datalab.rest.contracts.ComputationalAPI;
+import com.epam.datalab.rest.contracts.ExploratoryAPI;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.util.Objects;
+
+@Path("/library")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class LibraryResource extends DockerService implements DockerCommands {
+
+
+    @POST
+    @Path(ExploratoryAPI.EXPLORATORY + "/lib_list")
+    public String getLibList(@Auth UserInfo ui, LibListExploratoryDTO dto) throws JsonProcessingException {
+        return actionExploratory(ui.getName(), dto, DockerAction.LIB_LIST);
+    }
+
+    @POST
+    @Path(ExploratoryAPI.EXPLORATORY + "/lib_install")
+    public String libInstall(@Auth UserInfo ui, LibraryInstallDTO dto) throws JsonProcessingException {
+        return actionExploratory(ui.getName(), dto, DockerAction.LIB_INSTALL);
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL + "/lib_list")
+    public String getLibList(@Auth UserInfo ui, LibListComputationalDTO dto) throws JsonProcessingException {
+        return actionComputational(ui.getName(), dto, DockerAction.LIB_LIST);
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL + "/lib_install")
+    public String getLibList(@Auth UserInfo ui, LibraryInstallDTO dto) throws JsonProcessingException {
+        return actionComputational(ui.getName(), dto, DockerAction.LIB_INSTALL);
+    }
+
+    private String actionExploratory(String username, ExploratoryBaseDTO<?> dto, DockerAction action) throws JsonProcessingException {
+        log.debug("{} user {} exploratory environment {}", action, username, dto);
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallbackExploratory(action, uuid, dto));
+
+        RunDockerCommand runDockerCommand = getDockerCommandExploratory(dto, action, uuid);
+
+        commandExecutor.executeAsync(username, uuid, commandBuilder.buildCommand(runDockerCommand, dto));
+        return uuid;
+    }
+
+    private String actionComputational(String username, ExploratoryActionDTO<?> dto, DockerAction action) throws JsonProcessingException {
+        log.debug("{} user {} exploratory environment {}", action, username, dto);
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallbackComputational(action, uuid, dto));
+
+        RunDockerCommand runDockerCommand = getDockerCommandComputational(dto, action, uuid);
+
+        commandExecutor.executeAsync(username, uuid, commandBuilder.buildCommand(runDockerCommand, dto));
+        return uuid;
+    }
+
+    private RunDockerCommand getDockerCommandExploratory(ExploratoryBaseDTO<?> dto, DockerAction action, String uuid) {
+        return getDockerCommand(action, uuid)
+                .withName(nameContainer(dto.getEdgeUserName(), action.toString(), "exploratory",
+                        dto.getExploratoryName()))
+                .withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
+                .withResource(getResourceType())
+                .withImage(dto.getNotebookImage());
+    }
+
+    private RunDockerCommand getDockerCommandComputational(ExploratoryActionDTO<?> dto, DockerAction action,
+                                                           String uuid) {
+        RunDockerCommand runDockerCommand = getDockerCommand(action, uuid);
+        if (dto instanceof LibraryInstallDTO) {
+            LibraryInstallDTO newDTO = (LibraryInstallDTO) dto;
+            runDockerCommand.withName(nameContainer(dto.getEdgeUserName(), action.toString(),
+                    "computational", newDTO.getComputationalId()))
+                    .withVolumeForLog(configuration.getDockerLogDirectory(),
+                            DataEngineType.fromDockerImageName(newDTO.getComputationalImage()).getName())
+                    .withResource(DataEngineType.fromDockerImageName(newDTO.getComputationalImage()).getName())
+
+                    .withImage(newDTO.getComputationalImage());
+
+        } else {
+            LibListComputationalDTO newDTO = (LibListComputationalDTO) dto;
+
+            runDockerCommand.withName(nameContainer(dto.getEdgeUserName(), action.toString(),
+                    "computational", newDTO.getComputationalId()))
+                    .withVolumeForLog(configuration.getDockerLogDirectory(),
+                            DataEngineType.fromDockerImageName(newDTO.getComputationalImage()).getName())
+                    .withResource(DataEngineType.fromDockerImageName(newDTO.getComputationalImage()).getName())
+                    .withImage(newDTO.getComputationalImage());
+
+        }
+        return runDockerCommand;
+    }
+
+    private RunDockerCommand getDockerCommand(DockerAction action, String uuid) {
+        RunDockerCommand runDockerCommand = new RunDockerCommand()
+                .withInteractive()
+                .withVolumeForRootKeys(configuration.getKeyDirectory())
+                .withVolumeForResponse(configuration.getImagesDirectory())
+                .withRequestId(uuid)
+                .withConfKeyName(configuration.getAdminKey())
+                .withAction(action);
+        if (configuration.getCloudProvider() == CloudProvider.AZURE &&
+                Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
+                !configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
+            runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
+        }
+
+        return runDockerCommand;
+    }
+
+    private FileHandlerCallback getFileHandlerCallbackExploratory(DockerAction action, String uuid,
+                                                                  ExploratoryBaseDTO<?> dto) {
+        switch (action) {
+            case LIB_LIST:
+                final String group = ((LibListExploratoryDTO) dto).getLibCacheKey();
+                return new LibListCallbackHandler(selfService, DockerAction.LIB_LIST, uuid,
+                        dto.getCloudSettings().getIamUser(), group);
+            case LIB_INSTALL:
+                return new LibInstallCallbackHandler(selfService, action, uuid,
+                        dto.getCloudSettings().getIamUser(),
+                        (LibraryInstallDTO) dto);
+            default:
+                throw new IllegalArgumentException("Unknown action " + action);
+        }
+    }
+
+    private FileHandlerCallback getFileHandlerCallbackComputational(DockerAction action, String uuid,
+                                                                    ExploratoryBaseDTO<?> dto) {
+        switch (action) {
+            case LIB_LIST:
+                return new LibListCallbackHandler(selfService, action, uuid,
+                        dto.getCloudSettings().getIamUser(), ((LibListComputationalDTO) dto).getLibCacheKey());
+            case LIB_INSTALL:
+                return new LibInstallCallbackHandler(selfService, action, uuid,
+                        dto.getCloudSettings().getIamUser(), ((LibraryInstallDTO) dto));
+
+            default:
+                throw new IllegalArgumentException("Unknown action " + action);
+        }
+    }
+
+    public String getResourceType() {
+        return Directories.NOTEBOOK_LOG_DIRECTORY;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ProjectResource.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ProjectResource.java
new file mode 100644
index 0000000..f8c50cf
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ProjectResource.java
@@ -0,0 +1,76 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.dto.project.ProjectActionDTO;
+import com.epam.datalab.dto.project.ProjectCreateDTO;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+
+import javax.ws.rs.Consumes;
+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;
+
+@Path("infrastructure/project")
+public class ProjectResource {
+    private final ProjectService projectService;
+
+    @Inject
+    public ProjectResource(ProjectService projectService) {
+        this.projectService = projectService;
+    }
+
+    @Path("/create")
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createProject(@Auth UserInfo userInfo, ProjectCreateDTO dto) {
+        return Response.ok(projectService.create(userInfo, dto)).build();
+    }
+
+    @Path("/terminate")
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response terminateProject(@Auth UserInfo userInfo, ProjectActionDTO dto) {
+        return Response.ok(projectService.terminate(userInfo, dto)).build();
+    }
+
+    @Path("/start")
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response startProject(@Auth UserInfo userInfo, ProjectActionDTO dto) {
+        return Response.ok(projectService.start(userInfo, dto)).build();
+    }
+
+    @Path("/stop")
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response stopProject(@Auth UserInfo userInfo, ProjectActionDTO dto) {
+        return Response.ok(projectService.stop(userInfo, dto)).build();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ProvisioningHealthCheckResource.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ProvisioningHealthCheckResource.java
new file mode 100644
index 0000000..a252699
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ProvisioningHealthCheckResource.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("/healthcheck")
+@Produces(MediaType.APPLICATION_JSON)
+public class ProvisioningHealthCheckResource {
+    @Inject
+    private ProvisioningServiceApplicationConfiguration configuration;
+
+    @GET
+    public Response status(@Auth UserInfo ui) {
+        return Response.ok(configuration.getCloudProvider()).build();
+    }
+}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/aws/ComputationalResourceAws.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/aws/ComputationalResourceAws.java
new file mode 100644
index 0000000..1818b29
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/aws/ComputationalResourceAws.java
@@ -0,0 +1,197 @@
+/*
+ * 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.datalab.backendapi.resources.aws;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.handlers.ComputationalCallbackHandler;
+import com.epam.datalab.backendapi.core.response.handlers.ComputationalConfigure;
+import com.epam.datalab.backendapi.service.impl.DockerService;
+import com.epam.datalab.backendapi.service.impl.SparkClusterService;
+import com.epam.datalab.dto.aws.computational.AwsComputationalTerminateDTO;
+import com.epam.datalab.dto.aws.computational.ComputationalCreateAws;
+import com.epam.datalab.dto.aws.computational.SparkComputationalCreateAws;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.epam.datalab.dto.computational.ComputationalClusterConfigDTO;
+import com.epam.datalab.dto.computational.ComputationalStartDTO;
+import com.epam.datalab.dto.computational.ComputationalStopDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.contracts.ComputationalAPI;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import static com.epam.datalab.backendapi.core.commands.DockerAction.CREATE;
+import static com.epam.datalab.backendapi.core.commands.DockerAction.TERMINATE;
+
+@Path("/")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ComputationalResourceAws extends DockerService implements DockerCommands {
+
+    private static final DataEngineType EMR_DATA_ENGINE = DataEngineType.CLOUD_SERVICE;
+    @Inject
+    private ComputationalConfigure computationalConfigure;
+    @Inject
+    private SparkClusterService sparkClusterService;
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_CREATE_CLOUD_SPECIFIC)
+    public String create(@Auth UserInfo ui, ComputationalCreateAws dto) {
+        log.debug("Create computational resources {} for user {}: {}", dto.getComputationalName(), ui.getName(), dto);
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallback(CREATE, uuid, dto));
+        try {
+            long timeout = configuration.getResourceStatusPollTimeout().toSeconds();
+            commandExecutor.executeAsync(
+                    ui.getName(),
+                    uuid,
+                    commandBuilder.buildCommand(
+                            new RunDockerCommand()
+                                    .withInteractive()
+                                    .withName(nameContainer(dto.getEdgeUserName(), CREATE, dto.getExploratoryName(),
+                                            dto.getComputationalName()))
+                                    .withVolumeForRootKeys(configuration.getKeyDirectory())
+                                    .withVolumeForResponse(configuration.getImagesDirectory())
+                                    .withVolumeForLog(configuration.getDockerLogDirectory(), EMR_DATA_ENGINE.getName())
+                                    .withResource(EMR_DATA_ENGINE.getName())
+                                    .withRequestId(uuid)
+                                    .withEc2Role(configuration.getEmrEC2RoleDefault())
+                                    .withEmrTimeout(Long.toString(timeout))
+                                    .withServiceRole(configuration.getEmrServiceRoleDefault())
+                                    .withConfKeyName(configuration.getAdminKey())
+                                    .withActionCreate(DataEngineType.getDockerImageName(EMR_DATA_ENGINE)),
+                            dto
+                    )
+            );
+        } catch (Exception t) {
+            throw new DatalabException("Could not create computational resource cluster", t);
+        }
+        return uuid;
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC)
+    public String terminate(@Auth UserInfo ui, AwsComputationalTerminateDTO dto) {
+
+        log.debug("Terminate computational resources {} for user {}: {}", dto.getComputationalName(), ui.getName(),
+                dto);
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallback(TERMINATE, uuid, dto));
+        try {
+            commandExecutor.executeAsync(
+                    ui.getName(),
+                    uuid,
+                    commandBuilder.buildCommand(
+                            new RunDockerCommand()
+                                    .withInteractive()
+                                    .withName(nameContainer(dto.getEdgeUserName(), TERMINATE,
+                                            dto.getExploratoryName(), dto.getComputationalName()))
+                                    .withVolumeForRootKeys(configuration.getKeyDirectory())
+                                    .withVolumeForResponse(configuration.getImagesDirectory())
+                                    .withVolumeForLog(configuration.getDockerLogDirectory(), EMR_DATA_ENGINE.getName())
+                                    .withResource(EMR_DATA_ENGINE.getName())
+                                    .withRequestId(uuid)
+                                    .withConfKeyName(configuration.getAdminKey())
+                                    .withActionTerminate(DataEngineType.getDockerImageName(EMR_DATA_ENGINE)),
+                            dto
+                    )
+            );
+        } catch (JsonProcessingException t) {
+            throw new DatalabException("Could not terminate computational resources cluster", t);
+        }
+
+        return uuid;
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_CREATE_SPARK)
+    public String createSparkCluster(@Auth UserInfo ui, SparkComputationalCreateAws dto) {
+        log.debug("Create computational Spark resources {} for user {}: {}", dto.getComputationalName(), ui.getName(),
+                dto);
+
+        return sparkClusterService.create(ui, dto);
+    }
+
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_TERMINATE_SPARK)
+    public String terminateSparkCluster(@Auth UserInfo ui, AwsComputationalTerminateDTO dto) {
+        log.debug("Terminate computational Spark resource {} for user {}: {}", dto.getComputationalName(), ui.getName
+                (), dto);
+
+        return sparkClusterService.terminate(ui, dto);
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_STOP_SPARK)
+    public String stopSparkCluster(@Auth UserInfo ui, ComputationalStopDTO dto) {
+        log.debug("Stop computational Spark resources {} for user {}: {}",
+                dto.getComputationalName(), ui.getName(), dto);
+
+        return sparkClusterService.stop(ui, dto);
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_START_SPARK)
+    public String startSparkCluster(@Auth UserInfo ui, ComputationalStartDTO dto) {
+        log.debug("Start computational Spark resource {} for user {}: {}",
+                dto.getComputationalName(), ui.getName(), dto);
+
+        return sparkClusterService.start(ui, dto);
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_RECONFIGURE_SPARK)
+    public String reconfigureSparkCluster(@Auth UserInfo ui, ComputationalClusterConfigDTO config) {
+        log.debug("User is reconfiguring {} spark cluster for exploratory {}", ui.getName(),
+                config.getComputationalName(), config.getNotebookInstanceName());
+        return sparkClusterService.updateConfig(ui, config);
+    }
+
+    private FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, ComputationalBase<?> dto) {
+        return new ComputationalCallbackHandler(computationalConfigure, selfService, action, uuid, dto);
+    }
+
+    private String nameContainer(String user, DockerAction action, String exploratoryName, String name) {
+        return nameContainer(user, action.toString(), "computational", exploratoryName, name);
+    }
+
+    public String getResourceType() {
+        return Directories.DATA_ENGINE_SERVICE_LOG_DIRECTORY;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/aws/EdgeResourceAws.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/aws/EdgeResourceAws.java
new file mode 100644
index 0000000..1e0565b
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/aws/EdgeResourceAws.java
@@ -0,0 +1,94 @@
+/*
+ * 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.datalab.backendapi.resources.aws;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.response.handlers.EdgeCallbackHandler;
+import com.epam.datalab.backendapi.resources.base.EdgeService;
+import com.epam.datalab.dto.ResourceSysBaseDTO;
+import com.epam.datalab.dto.aws.edge.EdgeInfoAws;
+import com.epam.datalab.dto.aws.keyload.UploadFileAws;
+import com.epam.datalab.dto.base.keyload.UploadFileResult;
+import com.epam.datalab.util.FileUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.io.IOException;
+
+import static com.epam.datalab.rest.contracts.ApiCallbacks.EDGE;
+import static com.epam.datalab.rest.contracts.ApiCallbacks.KEY_LOADER;
+import static com.epam.datalab.rest.contracts.ApiCallbacks.STATUS_URI;
+
+/**
+ * Provides API to manage Edge node on AWS
+ */
+@Path("infrastructure/edge")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class EdgeResourceAws extends EdgeService {
+
+    public EdgeResourceAws() {
+        log.info("{} is initialized", getClass().getSimpleName());
+    }
+
+    @POST
+    @Path("/create")
+    public String create(@Auth UserInfo ui, UploadFileAws dto) throws IOException {
+        FileUtils.saveToFile(getKeyFilename(dto.getEdge().getEdgeUserName()), getKeyDirectory(), dto.getContent());
+        return action(ui.getName(), dto.getEdge(), dto.getEdge().getCloudSettings().getIamUser(), KEY_LOADER,
+                DockerAction.CREATE);
+    }
+
+    @POST
+    @Path("/start")
+    public String start(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
+        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI, DockerAction.START);
+    }
+
+    @POST
+    @Path("/stop")
+    public String stop(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
+        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI, DockerAction.STOP);
+    }
+
+    @POST
+    @Path("/terminate")
+    public String terminate(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
+        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI,
+                DockerAction.TERMINATE);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, String user, String
+            callbackURI) {
+        return new EdgeCallbackHandler(selfService, action, uuid, user, callbackURI,
+                EdgeInfoAws.class,
+                UploadFileResult.class);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/aws/ExploratoryResourceAws.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/aws/ExploratoryResourceAws.java
new file mode 100644
index 0000000..f036880
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/aws/ExploratoryResourceAws.java
@@ -0,0 +1,77 @@
+/*
+ * 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.datalab.backendapi.resources.aws;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.resources.base.ExploratoryService;
+import com.epam.datalab.dto.aws.exploratory.ExploratoryCreateAws;
+import com.epam.datalab.dto.exploratory.ExploratoryActionDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/exploratory")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class ExploratoryResourceAws {
+
+    @Inject
+    private ExploratoryService exploratoryService;
+
+
+    @Path("/create")
+    @POST
+    public String create(@Auth UserInfo ui, ExploratoryCreateAws dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.CREATE);
+    }
+
+    @Path("/start")
+    @POST
+    public String start(@Auth UserInfo ui, ExploratoryGitCredsUpdateDTO dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.START);
+    }
+
+    @Path("/terminate")
+    @POST
+    public String terminate(@Auth UserInfo ui, ExploratoryActionDTO<?> dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.TERMINATE);
+    }
+
+    @Path("/stop")
+    @POST
+    public String stop(@Auth UserInfo ui, ExploratoryActionDTO<?> dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.STOP);
+    }
+
+    @Path("/reconfigure_spark")
+    @POST
+    public String reconfigureSpark(@Auth UserInfo ui, ExploratoryReconfigureSparkClusterActionDTO dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.RECONFIGURE_SPARK);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/aws/InfrastructureResourceAws.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/aws/InfrastructureResourceAws.java
new file mode 100644
index 0000000..c88002c
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/aws/InfrastructureResourceAws.java
@@ -0,0 +1,49 @@
+/*
+ * 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.datalab.backendapi.resources.aws;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.resources.base.InfrastructureService;
+import com.epam.datalab.dto.UserEnvironmentResources;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/infrastructure")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class InfrastructureResourceAws extends InfrastructureService {
+    public InfrastructureResourceAws() {
+        log.info("{} is initialized", getClass().getSimpleName());
+    }
+
+    @Path("/status")
+    @POST
+    public String status(@Auth UserInfo ui, UserEnvironmentResources dto) {
+        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), DockerAction.STATUS);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java
new file mode 100644
index 0000000..effed2d
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java
@@ -0,0 +1,94 @@
+/*
+ * 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.datalab.backendapi.resources.azure;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.impl.SparkClusterService;
+import com.epam.datalab.dto.azure.computational.SparkComputationalCreateAzure;
+import com.epam.datalab.dto.computational.ComputationalClusterConfigDTO;
+import com.epam.datalab.dto.computational.ComputationalStartDTO;
+import com.epam.datalab.dto.computational.ComputationalStopDTO;
+import com.epam.datalab.dto.computational.ComputationalTerminateDTO;
+import com.epam.datalab.rest.contracts.ComputationalAPI;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ComputationalResourceAzure implements ComputationalAPI {
+
+    @Inject
+    private SparkClusterService sparkClusterService;
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_CREATE_SPARK)
+    public String create(@Auth UserInfo ui, SparkComputationalCreateAzure dto) {
+        log.debug("Create computational Spark resources {} for user {}: {}",
+                dto.getComputationalName(), ui.getName(), dto);
+
+        return sparkClusterService.create(ui, dto);
+    }
+
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_TERMINATE_SPARK)
+    public String terminate(@Auth UserInfo ui, ComputationalTerminateDTO dto) {
+        log.debug("Terminate computational Spark resources {} for user {}: {}",
+                dto.getComputationalName(), ui.getName(), dto);
+
+        return sparkClusterService.terminate(ui, dto);
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_STOP_SPARK)
+    public String stopSparkCluster(@Auth UserInfo ui, ComputationalStopDTO dto) {
+        log.debug("Stop computational Spark resources {} for user {}: {}",
+                dto.getComputationalName(), ui.getName(), dto);
+
+        return sparkClusterService.stop(ui, dto);
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_START_SPARK)
+    public String startSparkCluster(@Auth UserInfo ui, ComputationalStartDTO dto) {
+        log.debug("Start computational Spark resource {} for user {}: {}",
+                dto.getComputationalName(), ui.getName(), dto);
+
+        return sparkClusterService.start(ui, dto);
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_RECONFIGURE_SPARK)
+    public String reconfigureSparkCluster(@Auth UserInfo ui, ComputationalClusterConfigDTO config) {
+        log.debug("User is reconfiguring {} spark cluster for exploratory {}", ui.getName(),
+                config.getComputationalName(), config.getNotebookInstanceName());
+        return sparkClusterService.updateConfig(ui, config);
+    }
+
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/EdgeResourceAzure.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/EdgeResourceAzure.java
new file mode 100644
index 0000000..0d8a258
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/EdgeResourceAzure.java
@@ -0,0 +1,94 @@
+/*
+ * 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.datalab.backendapi.resources.azure;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.response.handlers.EdgeCallbackHandler;
+import com.epam.datalab.backendapi.resources.base.EdgeService;
+import com.epam.datalab.dto.ResourceSysBaseDTO;
+import com.epam.datalab.dto.azure.edge.EdgeInfoAzure;
+import com.epam.datalab.dto.azure.keyload.UploadFileAzure;
+import com.epam.datalab.dto.base.keyload.UploadFileResult;
+import com.epam.datalab.util.FileUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.io.IOException;
+
+import static com.epam.datalab.rest.contracts.ApiCallbacks.EDGE;
+import static com.epam.datalab.rest.contracts.ApiCallbacks.KEY_LOADER;
+import static com.epam.datalab.rest.contracts.ApiCallbacks.STATUS_URI;
+
+/**
+ * Provides API to manage Edge node on Azure
+ */
+@Path("infrastructure/edge")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class EdgeResourceAzure extends EdgeService {
+
+    public EdgeResourceAzure() {
+        log.info("{} is initialized", getClass().getSimpleName());
+    }
+
+    @POST
+    @Path("/create")
+    public String create(@Auth UserInfo ui, UploadFileAzure dto) throws IOException {
+        FileUtils.saveToFile(getKeyFilename(dto.getEdge().getEdgeUserName()), getKeyDirectory(), dto.getContent());
+        return action(ui.getName(), dto.getEdge(), dto.getEdge().getCloudSettings().getIamUser(), KEY_LOADER,
+                DockerAction.CREATE);
+    }
+
+    @POST
+    @Path("/start")
+    public String start(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
+        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI, DockerAction.START);
+    }
+
+    @POST
+    @Path("/stop")
+    public String stop(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
+        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI, DockerAction.STOP);
+    }
+
+    @POST
+    @Path("/terminate")
+    public String terminate(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
+        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI,
+                DockerAction.TERMINATE);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, String user, String
+            callbackURI) {
+        return new EdgeCallbackHandler(selfService, action, uuid, user, callbackURI,
+                EdgeInfoAzure.class,
+                UploadFileResult.class);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ExploratoryResourceAzure.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ExploratoryResourceAzure.java
new file mode 100644
index 0000000..d078239
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ExploratoryResourceAzure.java
@@ -0,0 +1,75 @@
+/*
+ * 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.datalab.backendapi.resources.azure;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.resources.base.ExploratoryService;
+import com.epam.datalab.dto.azure.exploratory.ExploratoryActionStartAzure;
+import com.epam.datalab.dto.azure.exploratory.ExploratoryActionStopAzure;
+import com.epam.datalab.dto.azure.exploratory.ExploratoryCreateAzure;
+import com.epam.datalab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/exploratory")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class ExploratoryResourceAzure {
+    @Inject
+    private ExploratoryService exploratoryService;
+
+    @Path("/create")
+    @POST
+    public String create(@Auth UserInfo ui, ExploratoryCreateAzure dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.CREATE);
+    }
+
+    @Path("/start")
+    @POST
+    public String start(@Auth UserInfo ui, ExploratoryActionStartAzure dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.START);
+    }
+
+    @Path("/terminate")
+    @POST
+    public String terminate(@Auth UserInfo ui, ExploratoryActionStopAzure dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.TERMINATE);
+    }
+
+    @Path("/stop")
+    @POST
+    public String stop(@Auth UserInfo ui, ExploratoryActionStopAzure dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.STOP);
+    }
+
+    @Path("/reconfigure_spark")
+    @POST
+    public String reconfigureSpark(@Auth UserInfo ui, ExploratoryReconfigureSparkClusterActionDTO dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.RECONFIGURE_SPARK);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/InfrastructureResourceAzure.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/InfrastructureResourceAzure.java
new file mode 100644
index 0000000..01650b7
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/InfrastructureResourceAzure.java
@@ -0,0 +1,50 @@
+/*
+ * 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.datalab.backendapi.resources.azure;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.resources.base.InfrastructureService;
+import com.epam.datalab.dto.UserEnvironmentResources;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/infrastructure")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class InfrastructureResourceAzure extends InfrastructureService {
+
+    public InfrastructureResourceAzure() {
+        log.info("{} is initialized", getClass().getSimpleName());
+    }
+
+    @Path("/status")
+    @POST
+    public String status(@Auth UserInfo ui, UserEnvironmentResources dto) {
+        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), DockerAction.STATUS);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/base/EdgeService.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/base/EdgeService.java
new file mode 100644
index 0000000..55944aa
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/base/EdgeService.java
@@ -0,0 +1,108 @@
+/*
+ * 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.datalab.backendapi.resources.base;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.CommandBuilder;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.ICommandExecutor;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.folderlistener.FolderListenerExecutor;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.ResourceSysBaseDTO;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.KeyAPI;
+import com.epam.datalab.util.UsernameUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.inject.Inject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Objects;
+
+public abstract class EdgeService implements DockerCommands {
+
+	private final Logger logger = LoggerFactory.getLogger(getClass());
+
+	@Inject
+	protected RESTService selfService;
+	@Inject
+	private ProvisioningServiceApplicationConfiguration configuration;
+	@Inject
+	private FolderListenerExecutor folderListenerExecutor;
+	@Inject
+	private ICommandExecutor commandExecutor;
+	@Inject
+	private CommandBuilder commandBuilder;
+
+	@Override
+	public String getResourceType() {
+		return Directories.EDGE_LOG_DIRECTORY;
+	}
+
+	protected String action(String username, ResourceSysBaseDTO<?> dto, String iamUser, String callbackURI,
+							DockerAction action) throws JsonProcessingException {
+		logger.debug("{} EDGE node for user {}: {}", action, username, dto);
+		String uuid = DockerCommands.generateUUID();
+
+		folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
+				configuration.getKeyLoaderPollTimeout(),
+				getFileHandlerCallback(action, uuid, iamUser, callbackURI));
+
+		RunDockerCommand runDockerCommand = new RunDockerCommand()
+				.withInteractive()
+				.withName(nameContainer(dto.getEdgeUserName(), action))
+				.withVolumeForRootKeys(getKeyDirectory())
+				.withVolumeForResponse(configuration.getKeyLoaderDirectory())
+				.withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
+				.withResource(getResourceType())
+				.withRequestId(uuid)
+				.withConfKeyName(configuration.getAdminKey())
+				.withImage(configuration.getEdgeImage())
+				.withAction(action);
+		if (configuration.getCloudProvider() == CloudProvider.AZURE &&
+				Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
+				!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
+			runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
+		}
+
+		commandExecutor.executeAsync(username, uuid, commandBuilder.buildCommand(runDockerCommand, dto));
+		return uuid;
+	}
+
+	protected abstract FileHandlerCallback getFileHandlerCallback(DockerAction action,
+																  String uuid, String user, String callbackURI);
+
+	private String nameContainer(String user, DockerAction action) {
+		return nameContainer(user, action.toString(), getResourceType());
+	}
+
+	protected String getKeyDirectory() {
+		return configuration.getKeyDirectory();
+	}
+
+	protected String getKeyFilename(String edgeUserName) {
+		return UsernameUtils.replaceWhitespaces(edgeUserName) + KeyAPI.KEY_EXTENTION;
+	}
+
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/base/ExploratoryService.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/base/ExploratoryService.java
new file mode 100644
index 0000000..2116670
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/base/ExploratoryService.java
@@ -0,0 +1,79 @@
+/*
+ * 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.datalab.backendapi.resources.base;
+
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.handlers.ExploratoryCallbackHandler;
+import com.epam.datalab.backendapi.service.impl.DockerService;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.exploratory.ExploratoryBaseDTO;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Objects;
+
+@Slf4j
+public class ExploratoryService extends DockerService implements DockerCommands {
+
+    public String action(String username, ExploratoryBaseDTO<?> dto, DockerAction action) throws JsonProcessingException {
+        log.debug("{} exploratory environment", action);
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallback(action, uuid, dto));
+
+        RunDockerCommand runDockerCommand = new RunDockerCommand()
+                .withInteractive()
+                .withName(nameContainer(dto.getEdgeUserName(), action, dto.getExploratoryName()))
+                .withVolumeForRootKeys(configuration.getKeyDirectory())
+                .withVolumeForResponse(configuration.getImagesDirectory())
+                .withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
+                .withResource(getResourceType())
+                .withRequestId(uuid)
+                .withConfKeyName(configuration.getAdminKey())
+                .withImage(dto.getNotebookImage())
+                .withAction(action);
+        if (configuration.getCloudProvider() == CloudProvider.AZURE &&
+                Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
+                !configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
+            runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
+        }
+
+        commandExecutor.executeAsync(username, uuid, commandBuilder.buildCommand(runDockerCommand, dto));
+        return uuid;
+    }
+
+    public String getResourceType() {
+        return Directories.NOTEBOOK_LOG_DIRECTORY;
+    }
+
+    private FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, ExploratoryBaseDTO<?> dto) {
+        return new ExploratoryCallbackHandler(selfService, action, uuid, dto.getCloudSettings().getIamUser(),
+                dto.getProject(), dto.getExploratoryName());
+    }
+
+    private String nameContainer(String user, DockerAction action, String name) {
+        return nameContainer(user, action.toString(), "exploratory", name);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/base/InfrastructureService.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/base/InfrastructureService.java
new file mode 100644
index 0000000..e9c29ce
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/base/InfrastructureService.java
@@ -0,0 +1,157 @@
+/*
+ * 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.datalab.backendapi.resources.base;
+
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.CommandBuilder;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.ICommandExecutor;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.folderlistener.FolderListenerExecutor;
+import com.epam.datalab.backendapi.core.response.handlers.ResourcesStatusCallbackHandler;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.UserEnvironmentResources;
+import com.epam.datalab.dto.status.EnvResource;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.process.model.ProcessInfo;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.epam.datalab.backendapi.core.commands.DockerAction.STATUS;
+import static java.util.stream.Collectors.toList;
+
+@Slf4j
+public abstract class InfrastructureService implements DockerCommands {
+    @Inject
+    private RESTService selfService;
+    @Inject
+    private ProvisioningServiceApplicationConfiguration configuration;
+    @Inject
+    private FolderListenerExecutor folderListenerExecutor;
+    @Inject
+    private ICommandExecutor commandExecutor;
+    @Inject
+    private CommandBuilder commandBuilder;
+
+    private static final String CONTAINER_NAME_REGEX_FORMAT = "%s_[^_\\W]+_%s(|_%s)_\\d+";
+
+    public String action(String username, UserEnvironmentResources dto, String iamUser, DockerAction dockerAction) {
+        log.trace("Request the status of resources for user {}: {}", username, dto);
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getRequestEnvStatusTimeout(),
+                getFileHandlerCallback(dockerAction, uuid, iamUser));
+        try {
+
+            removeResourcesWithRunningContainers(username, dto);
+
+            if (!(dto.getResourceList().getHostList().isEmpty() && dto.getResourceList().getClusterList().isEmpty())) {
+                log.trace("Request the status of resources for user {} after filtering: {}", username, dto);
+                RunDockerCommand runDockerCommand = new RunDockerCommand()
+                        .withInteractive()
+                        .withName(nameContainer(dto.getEdgeUserName(), STATUS, "resources"))
+                        .withVolumeForRootKeys(configuration.getKeyDirectory())
+                        .withVolumeForResponse(configuration.getImagesDirectory())
+                        .withVolumeForLog(configuration.getDockerLogDirectory(), Directories.EDGE_LOG_DIRECTORY)
+                        .withResource(getResourceType())
+                        .withRequestId(uuid)
+                        .withConfKeyName(configuration.getAdminKey())
+                        .withActionStatus(configuration.getEdgeImage());
+                if (configuration.getCloudProvider() == CloudProvider.AZURE &&
+                        Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
+                        !configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
+                    runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
+                }
+
+                commandExecutor.executeAsync(username, uuid, commandBuilder.buildCommand(runDockerCommand, dto));
+            } else {
+                log.debug("Skipping calling status command. Resource lists are empty");
+            }
+        } catch (Exception e) {
+            throw new DatalabException("Docker's command \"" + getResourceType() + "\" is fail: " + e.getLocalizedMessage
+                    (), e);
+        }
+        return uuid;
+    }
+
+    private void removeResourcesWithRunningContainers(String username, UserEnvironmentResources dto)
+            throws Exception {
+
+        final ProcessInfo processInfo = commandExecutor.executeSync(username, DockerCommands.generateUUID(),
+                String.format(DockerCommands
+                        .GET_RUNNING_CONTAINERS_FOR_USER, dto.getEdgeUserName()));
+        final String processInfoStdOut = processInfo.getStdOut();
+
+        if (StringUtils.isNoneEmpty(processInfoStdOut)) {
+            final List<String> runningContainerNames = Arrays.asList(processInfoStdOut.split("\n"));
+            log.info("Running containers for users: {}", runningContainerNames);
+            final List<EnvResource> hostList = filter(dto.getEdgeUserName(), runningContainerNames, dto
+                    .getResourceList()
+                    .getHostList());
+            final List<EnvResource> clusterList = filter(dto.getEdgeUserName(), runningContainerNames, dto
+                    .getResourceList()
+                    .getClusterList());
+
+            dto.getResourceList().setHostList(hostList);
+            dto.getResourceList().setClusterList(clusterList);
+
+        }
+    }
+
+    private List<EnvResource> filter(String username, List<String> runningContainerNames, List<EnvResource> hostList) {
+        return hostList
+                .stream()
+                .filter(envResource -> hasNotCorrespondingRunningContainer(username, runningContainerNames,
+                        envResource))
+                .map(envResource -> new EnvResource().withId(envResource.getId()).withStatus(envResource.getStatus()))
+                .collect(toList());
+    }
+
+    private boolean hasNotCorrespondingRunningContainer(String username, List<String> runningContainerNames,
+                                                        EnvResource
+                                                                envResource) {
+        final String regex = String.format(CONTAINER_NAME_REGEX_FORMAT, username, envResource
+                .getResourceType().name().toLowerCase(), Optional.ofNullable(envResource.getName()).orElse(""));
+        return runningContainerNames.stream().noneMatch(container -> container.matches(regex));
+    }
+
+    protected FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, String user) {
+        return new ResourcesStatusCallbackHandler(selfService, action, uuid, user);
+    }
+
+    private String nameContainer(String user, DockerAction action, String name) {
+        return nameContainer(user, action.toString(), name);
+    }
+
+    public String getResourceType() {
+        return "status";
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/base/KeyResource.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/base/KeyResource.java
new file mode 100644
index 0000000..0f0e8e1
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/base/KeyResource.java
@@ -0,0 +1,86 @@
+/*
+ * 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.datalab.backendapi.resources.base;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.service.impl.KeyService;
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyDTO;
+import com.epam.datalab.rest.contracts.KeyAPI;
+import com.epam.datalab.util.FileUtils;
+import com.epam.datalab.util.UsernameUtils;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.io.IOException;
+import java.util.UUID;
+
+/**
+ * Provides API for reuploading keys
+ */
+@Path("key")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class KeyResource {
+
+	private final KeyService keyService;
+	private final ProvisioningServiceApplicationConfiguration configuration;
+
+	@Inject
+	public KeyResource(KeyService keyService, ProvisioningServiceApplicationConfiguration configuration) {
+		this.keyService = keyService;
+		this.configuration = configuration;
+	}
+
+
+	@Path("/reupload")
+	@POST
+	public String reuploadKey(@Auth UserInfo ui, @DefaultValue("true") @QueryParam("is_primary_reuploading")
+			boolean isPrimaryReuploading, ReuploadKeyDTO dto) throws IOException {
+		if (isPrimaryReuploading) {
+			replaceKeyfile(dto);
+		}
+		keyService.reuploadKeyAction(ui.getName(), dto, DockerAction.REUPLOAD_KEY);
+		return UUID.randomUUID().toString();
+	}
+
+	@GET
+	public String getAdminKey(@Auth UserInfo userInfo) {
+		return keyService.getAdminKey();
+	}
+
+	private void replaceKeyfile(ReuploadKeyDTO dto) throws IOException {
+		String edgeUserName = dto.getEdgeUserName();
+		String filename = UsernameUtils.replaceWhitespaces(edgeUserName) + KeyAPI.KEY_EXTENTION;
+		FileUtils.deleteFile(filename, configuration.getKeyDirectory());
+		FileUtils.saveToFile(filename, configuration.getKeyDirectory(), dto.getContent());
+	}
+
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/ComputationalResourceGcp.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/ComputationalResourceGcp.java
new file mode 100644
index 0000000..0ff68f0
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/ComputationalResourceGcp.java
@@ -0,0 +1,197 @@
+/*
+ * 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.datalab.backendapi.resources.gcp;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.handlers.ComputationalCallbackHandler;
+import com.epam.datalab.backendapi.core.response.handlers.ComputationalConfigure;
+import com.epam.datalab.backendapi.service.impl.DockerService;
+import com.epam.datalab.backendapi.service.impl.SparkClusterService;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.epam.datalab.dto.computational.ComputationalClusterConfigDTO;
+import com.epam.datalab.dto.computational.ComputationalStartDTO;
+import com.epam.datalab.dto.computational.ComputationalStopDTO;
+import com.epam.datalab.dto.gcp.computational.ComputationalCreateGcp;
+import com.epam.datalab.dto.gcp.computational.GcpComputationalTerminateDTO;
+import com.epam.datalab.dto.gcp.computational.SparkComputationalCreateGcp;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.contracts.ComputationalAPI;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import static com.epam.datalab.backendapi.core.commands.DockerAction.CREATE;
+import static com.epam.datalab.backendapi.core.commands.DockerAction.TERMINATE;
+
+
+@Path("/")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ComputationalResourceGcp extends DockerService implements DockerCommands {
+
+    @Inject
+    private ComputationalConfigure computationalConfigure;
+    @Inject
+    private SparkClusterService sparkClusterService;
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_CREATE_CLOUD_SPECIFIC)
+    public String create(@Auth UserInfo ui, ComputationalCreateGcp dto) {
+        log.debug("Create computational resources {} for user {}: {}", dto.getComputationalName(), ui.getName(), dto);
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallback(CREATE, uuid, dto));
+        try {
+            commandExecutor.executeAsync(
+                    ui.getName(),
+                    uuid,
+                    commandBuilder.buildCommand(
+                            new RunDockerCommand()
+                                    .withInteractive()
+                                    .withName(nameContainer(dto.getEdgeUserName(), CREATE,
+                                            dto.getExploratoryName(), dto.getComputationalName()))
+                                    .withVolumeForRootKeys(configuration.getKeyDirectory())
+                                    .withVolumeForResponse(configuration.getImagesDirectory())
+                                    .withVolumeForLog(configuration.getDockerLogDirectory(), DataEngineType
+                                            .CLOUD_SERVICE.getName())
+                                    .withResource(DataEngineType.CLOUD_SERVICE.getName())
+                                    .withRequestId(uuid)
+                                    .withConfKeyName(configuration.getAdminKey())
+                                    .withActionCreate(DataEngineType.getDockerImageName(DataEngineType.CLOUD_SERVICE)),
+                            dto
+                    )
+            );
+        } catch (Exception t) {
+            throw new DatalabException("Could not create computational resource cluster", t);
+        }
+        return uuid;
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC)
+    public String terminate(@Auth UserInfo ui, GcpComputationalTerminateDTO dto) {
+
+        log.debug("Terminate computational resources {} for user {}: {}", dto.getComputationalName(), ui.getName(),
+                dto);
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallback(TERMINATE, uuid, dto));
+        try {
+            commandExecutor.executeAsync(
+                    ui.getName(),
+                    uuid,
+                    commandBuilder.buildCommand(
+                            new RunDockerCommand()
+                                    .withInteractive()
+                                    .withName(nameContainer(dto.getEdgeUserName(), TERMINATE,
+                                            dto.getExploratoryName(), dto.getComputationalName()))
+                                    .withVolumeForRootKeys(configuration.getKeyDirectory())
+                                    .withVolumeForResponse(configuration.getImagesDirectory())
+                                    .withVolumeForLog(configuration.getDockerLogDirectory(), DataEngineType
+                                            .CLOUD_SERVICE.getName())
+                                    .withResource(DataEngineType.CLOUD_SERVICE.getName())
+                                    .withRequestId(uuid)
+                                    .withConfKeyName(configuration.getAdminKey())
+                                    .withActionTerminate(DataEngineType.getDockerImageName(DataEngineType
+                                            .CLOUD_SERVICE)),
+                            dto
+                    )
+            );
+        } catch (JsonProcessingException t) {
+            throw new DatalabException("Could not terminate computational resources cluster", t);
+        }
+
+        return uuid;
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_CREATE_SPARK)
+    public String createSparkCluster(@Auth UserInfo ui, SparkComputationalCreateGcp dto) {
+        log.debug("Create computational Spark resources {} for user {}: {}", dto.getComputationalName(), ui.getName(),
+                dto);
+
+        return sparkClusterService.create(ui, dto);
+    }
+
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_TERMINATE_SPARK)
+    public String terminateSparkCluster(@Auth UserInfo ui, GcpComputationalTerminateDTO dto) {
+        log.debug("Terminate computational Spark resources {} for user {}: {}", dto.getComputationalName(), ui.getName
+                (), dto);
+
+        return sparkClusterService.terminate(ui, dto);
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_STOP_SPARK)
+    public String stopSparkCluster(@Auth UserInfo ui, ComputationalStopDTO dto) {
+        log.debug("Stop computational Spark resources {} for user {}: {}",
+                dto.getComputationalName(), ui.getName(), dto);
+
+        return sparkClusterService.stop(ui, dto);
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_START_SPARK)
+    public String startSparkCluster(@Auth UserInfo ui, ComputationalStartDTO dto) {
+        log.debug("Start computational Spark resource {} for user {}: {}",
+                dto.getComputationalName(), ui.getName(), dto);
+
+        return sparkClusterService.start(ui, dto);
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_RECONFIGURE_SPARK)
+    public String reconfigureSparkCluster(@Auth UserInfo ui, ComputationalClusterConfigDTO config) {
+        log.debug("User is reconfiguring {} spark cluster for exploratory {}", ui.getName(),
+                config.getComputationalName(), config.getNotebookInstanceName());
+        return sparkClusterService.updateConfig(ui, config);
+    }
+
+    private FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, ComputationalBase<?> dto) {
+        return new ComputationalCallbackHandler(computationalConfigure, selfService, action, uuid, dto);
+    }
+
+    private String nameContainer(String user, DockerAction action, String exploratoryName, String name) {
+        return nameContainer(user, action.toString(), "computational", exploratoryName, name);
+    }
+
+    @Override
+    public String getResourceType() {
+        return Directories.DATA_ENGINE_SERVICE_LOG_DIRECTORY;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/EdgeResourceGcp.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/EdgeResourceGcp.java
new file mode 100644
index 0000000..654f660
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/EdgeResourceGcp.java
@@ -0,0 +1,96 @@
+/*
+ * 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.datalab.backendapi.resources.gcp;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.response.handlers.EdgeCallbackHandler;
+import com.epam.datalab.backendapi.resources.base.EdgeService;
+import com.epam.datalab.dto.ResourceSysBaseDTO;
+import com.epam.datalab.dto.base.keyload.UploadFileResult;
+import com.epam.datalab.dto.gcp.edge.EdgeInfoGcp;
+import com.epam.datalab.dto.gcp.keyload.UploadFileGcp;
+import com.epam.datalab.util.FileUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.io.IOException;
+
+import static com.epam.datalab.rest.contracts.ApiCallbacks.EDGE;
+import static com.epam.datalab.rest.contracts.ApiCallbacks.KEY_LOADER;
+import static com.epam.datalab.rest.contracts.ApiCallbacks.STATUS_URI;
+
+/**
+ * Provides API to manage Edge node on GCP
+ */
+@Path("infrastructure/edge")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class EdgeResourceGcp extends EdgeService {
+
+    public EdgeResourceGcp() {
+        log.info("{} is initialized", getClass().getSimpleName());
+    }
+
+    @POST
+    @Path("/create")
+    public String create(@Auth UserInfo ui, UploadFileGcp dto) throws IOException {
+        FileUtils.saveToFile(getKeyFilename(dto.getEdge().getEdgeUserName()), getKeyDirectory(), dto.getContent());
+        return action(ui.getName(), dto.getEdge(), dto.getEdge().getCloudSettings().getIamUser(), KEY_LOADER,
+                DockerAction.CREATE);
+    }
+
+    @POST
+    @Path("/start")
+    public String start(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
+        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI, DockerAction.START);
+    }
+
+    @POST
+    @Path("/stop")
+    public String stop(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
+        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI, DockerAction.STOP);
+    }
+
+
+    @POST
+    @Path("/terminate")
+    public String terminate(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
+        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI,
+                DockerAction.TERMINATE);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, String user, String
+            callbackURI) {
+        return new EdgeCallbackHandler(selfService, action, uuid, user, callbackURI,
+                EdgeInfoGcp.class,
+                UploadFileResult.class);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/ExploratoryResourceGcp.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/ExploratoryResourceGcp.java
new file mode 100644
index 0000000..c946ff7
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/ExploratoryResourceGcp.java
@@ -0,0 +1,77 @@
+/*
+ * 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.datalab.backendapi.resources.gcp;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.resources.base.ExploratoryService;
+import com.epam.datalab.dto.exploratory.ExploratoryActionDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
+import com.epam.datalab.dto.gcp.exploratory.ExploratoryCreateGcp;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/exploratory")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class ExploratoryResourceGcp {
+
+    @Inject
+    private ExploratoryService exploratoryService;
+
+
+    @Path("/create")
+    @POST
+    public String create(@Auth UserInfo ui, ExploratoryCreateGcp dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.CREATE);
+    }
+
+    @Path("/start")
+    @POST
+    public String start(@Auth UserInfo ui, ExploratoryGitCredsUpdateDTO dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.START);
+    }
+
+    @Path("/terminate")
+    @POST
+    public String terminate(@Auth UserInfo ui, ExploratoryActionDTO<?> dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.TERMINATE);
+    }
+
+    @Path("/stop")
+    @POST
+    public String stop(@Auth UserInfo ui, ExploratoryActionDTO<?> dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.STOP);
+    }
+
+    @Path("/reconfigure_spark")
+    @POST
+    public String reconfigureSpark(@Auth UserInfo ui, ExploratoryReconfigureSparkClusterActionDTO dto) throws JsonProcessingException {
+        return exploratoryService.action(ui.getName(), dto, DockerAction.RECONFIGURE_SPARK);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/InfrastructureResourceGcp.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/InfrastructureResourceGcp.java
new file mode 100644
index 0000000..f15f63f
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/InfrastructureResourceGcp.java
@@ -0,0 +1,49 @@
+/*
+ * 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.datalab.backendapi.resources.gcp;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.resources.base.InfrastructureService;
+import com.epam.datalab.dto.UserEnvironmentResources;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/infrastructure")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class InfrastructureResourceGcp extends InfrastructureService {
+    public InfrastructureResourceGcp() {
+        log.info("{} is initialized", getClass().getSimpleName());
+    }
+
+    @Path("/status")
+    @POST
+    public String status(@Auth UserInfo ui, UserEnvironmentResources dto) {
+        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), DockerAction.STATUS);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/BucketService.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/BucketService.java
new file mode 100644
index 0000000..67e6583
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/BucketService.java
@@ -0,0 +1,41 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.dto.bucket.BucketDTO;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.util.List;
+
+public interface BucketService {
+    String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
+
+    List<BucketDTO> getObjects(String bucket);
+
+    void uploadObject(String bucket, String object, InputStream stream, String contentType, long fileSize);
+
+    void uploadFolder(UserInfo userInfo, String bucket, String folder);
+
+    void downloadObject(String bucket, String object, HttpServletResponse resp);
+
+    void deleteObjects(String bucket, List<String> objects);
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/CheckInactivityService.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/CheckInactivityService.java
new file mode 100644
index 0000000..0086d8e
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/CheckInactivityService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.dto.computational.ComputationalCheckInactivityDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryCheckInactivityAction;
+
+public interface CheckInactivityService {
+    String checkComputationalInactivity(String userName, ComputationalCheckInactivityDTO dto);
+
+    String checkExploratoryInactivity(String userName, ExploratoryCheckInactivityAction dto);
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/ProjectService.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/ProjectService.java
new file mode 100644
index 0000000..d919d87
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/ProjectService.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.dto.project.ProjectActionDTO;
+import com.epam.datalab.dto.project.ProjectCreateDTO;
+
+public interface ProjectService {
+
+    String create(UserInfo userInfo, ProjectCreateDTO projectCreateDTO);
+
+    String terminate(UserInfo userInfo, ProjectActionDTO dto);
+
+    String start(UserInfo userInfo, ProjectActionDTO dto);
+
+    String stop(UserInfo userInfo, ProjectActionDTO dto);
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/RestoreCallbackHandlerService.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/RestoreCallbackHandlerService.java
new file mode 100644
index 0000000..e619dc6
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/RestoreCallbackHandlerService.java
@@ -0,0 +1,25 @@
+/*
+ * 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.datalab.backendapi.service;
+
+@FunctionalInterface
+public interface RestoreCallbackHandlerService {
+    void restore();
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/CheckInactivityServiceImpl.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/CheckInactivityServiceImpl.java
new file mode 100644
index 0000000..1d9aa16
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/CheckInactivityServiceImpl.java
@@ -0,0 +1,129 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.handlers.CheckInactivityCallbackHandler;
+import com.epam.datalab.backendapi.service.CheckInactivityService;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.ResourceBaseDTO;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.computational.ComputationalCheckInactivityDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryCheckInactivityAction;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.google.inject.Singleton;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Objects;
+
+@Slf4j
+@Singleton
+public class CheckInactivityServiceImpl extends DockerService implements CheckInactivityService, DockerCommands {
+
+
+    @Override
+    public String checkComputationalInactivity(String userName, ComputationalCheckInactivityDTO dto) {
+        String uuid = DockerCommands.generateUUID();
+        startComputationalCallbackListener(userName, dto, uuid);
+        final RunDockerCommand runDockerCommand = new RunDockerCommand()
+                .withInteractive()
+                .withRemove()
+                .withName(nameContainer(uuid, DockerAction.CHECK_INACTIVITY.toString()))
+                .withVolumeForRootKeys(configuration.getKeyDirectory())
+                .withVolumeForResponse(configuration.getKeyLoaderDirectory())
+                .withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
+                .withResource(DataEngineType.fromDockerImageName(dto.getImage()) == DataEngineType.SPARK_STANDALONE ?
+                        Directories.DATA_ENGINE_LOG_DIRECTORY :
+                        Directories.DATA_ENGINE_SERVICE_LOG_DIRECTORY)
+                .withRequestId(uuid)
+                .withConfKeyName(configuration.getAdminKey())
+                .withImage(dto.getNotebookImage())
+                .withAction(DockerAction.CHECK_INACTIVITY);
+        if (configuration.getCloudProvider() == CloudProvider.AZURE &&
+                Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
+                !configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
+            runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
+        }
+
+        runDockerCmd(userName, uuid, runDockerCommand, dto);
+        return uuid;
+    }
+
+    @Override
+    public String checkExploratoryInactivity(String userName, ExploratoryCheckInactivityAction dto) {
+        String uuid = DockerCommands.generateUUID();
+        startExploratoryCallbackListener(userName, dto, uuid);
+        final RunDockerCommand runDockerCommand = new RunDockerCommand()
+                .withInteractive()
+                .withRemove()
+                .withName(nameContainer(uuid, DockerAction.CHECK_INACTIVITY.toString()))
+                .withVolumeForRootKeys(configuration.getKeyDirectory())
+                .withVolumeForResponse(configuration.getKeyLoaderDirectory())
+                .withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
+                .withResource(Directories.NOTEBOOK_LOG_DIRECTORY)
+                .withRequestId(uuid)
+                .withConfKeyName(configuration.getAdminKey())
+                .withImage(dto.getNotebookImage())
+                .withAction(DockerAction.CHECK_INACTIVITY);
+        if (configuration.getCloudProvider() == CloudProvider.AZURE &&
+                Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
+                !configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
+            runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
+        }
+
+        runDockerCmd(userName, uuid, runDockerCommand, dto);
+        return uuid;
+    }
+
+    private void startComputationalCallbackListener(String userName, ComputationalCheckInactivityDTO dto,
+                                                    String uuid) {
+        final CheckInactivityCallbackHandler handler = new CheckInactivityCallbackHandler(
+                selfService, ApiCallbacks.CHECK_INACTIVITY_COMPUTATIONAL_URI, userName, uuid,
+                dto.getExploratoryName(), dto.getComputationalName());
+        folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
+                configuration.getKeyLoaderPollTimeout(), handler);
+    }
+
+    private void startExploratoryCallbackListener(String userName, ExploratoryCheckInactivityAction dto, String uuid) {
+        final CheckInactivityCallbackHandler handler = new CheckInactivityCallbackHandler(
+                selfService, ApiCallbacks.CHECK_INACTIVITY_EXPLORATORY_URI, userName, uuid,
+                dto.getExploratoryName());
+        folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
+                configuration.getKeyLoaderPollTimeout(), handler);
+    }
+
+    private void runDockerCmd(String userName, String uuid, RunDockerCommand dockerCmd, ResourceBaseDTO<?> dto) {
+        try {
+            final String command = commandBuilder.buildCommand(dockerCmd, dto);
+            log.trace("Docker command: {}", command);
+            commandExecutor.executeAsync(userName, uuid, command);
+        } catch (Exception e) {
+            log.error("Exception occured during reuploading key: {} for command {}", e.getLocalizedMessage(),
+                    dockerCmd.toCMD(), e);
+        }
+    }
+
+    @Override
+    public String getResourceType() {
+        return Directories.NOTEBOOK_LOG_DIRECTORY;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/DockerService.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/DockerService.java
new file mode 100644
index 0000000..4a08f69
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/DockerService.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.commands.CommandBuilder;
+import com.epam.datalab.backendapi.core.commands.ICommandExecutor;
+import com.epam.datalab.backendapi.core.response.folderlistener.FolderListenerExecutor;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Inject;
+
+public abstract class DockerService {
+
+    @Inject
+    protected ProvisioningServiceApplicationConfiguration configuration;
+    @Inject
+    protected FolderListenerExecutor folderListenerExecutor;
+    @Inject
+    protected ICommandExecutor commandExecutor;
+    @Inject
+    protected CommandBuilder commandBuilder;
+    @Inject
+    protected RESTService selfService;
+
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/KeyService.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/KeyService.java
new file mode 100644
index 0000000..443d6a4
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/KeyService.java
@@ -0,0 +1,146 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.handlers.ReuploadKeyCallbackHandler;
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyCallbackDTO;
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.model.ResourceData;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+
+import static java.lang.String.format;
+import static java.nio.file.Files.readAllBytes;
+import static java.nio.file.Paths.get;
+
+@Slf4j
+@Singleton
+public class KeyService extends DockerService implements DockerCommands {
+
+    private static final String REUPLOAD_KEY_ACTION = "reupload_key";
+
+    private final ProvisioningServiceApplicationConfiguration conf;
+
+    @Inject
+    public KeyService(ProvisioningServiceApplicationConfiguration conf) {
+        this.conf = conf;
+    }
+
+
+    public void reuploadKeyAction(String userName, ReuploadKeyDTO dto, DockerAction action) {
+        log.debug("{} for edge user {}", action, dto.getEdgeUserName());
+
+        long count = dto.getResources()
+                .stream()
+                .map(resourceData -> buildCallbackDTO(resourceData, getUuid(), dto))
+                .peek(callbackDto -> startCallbackListener(userName, callbackDto))
+                .peek(callbackDto ->
+                        runDockerCmd(userName, callbackDto.getId(), buildRunDockerCommand(callbackDto, action),
+                                buildDockerCommandDTO(callbackDto)))
+                .count();
+        log.debug("Executed {} Docker commands", count);
+    }
+
+    public String getAdminKey() {
+        try {
+            return new String(readAllBytes(get(format("%s/%s.pem", conf.getKeyDirectory(), conf.getAdminKey()))));
+        } catch (IOException e) {
+            log.error("Can not read admin key: {}", e.getMessage());
+            throw new DatalabException("Can not read admin key: " + e.getMessage(), e);
+        }
+    }
+
+    private String getUuid() {
+        return DockerCommands.generateUUID();
+    }
+
+    private void runDockerCmd(String userName, String uuid, RunDockerCommand runDockerCommand,
+                              ReuploadKeyCallbackDTO callbackDto) {
+        try {
+            final String command = commandBuilder.buildCommand(runDockerCommand, callbackDto);
+            log.trace("Docker command: {}", command);
+            commandExecutor.executeAsync(userName, uuid, command);
+        } catch (Exception e) {
+            log.error("Exception occured during reuploading key: {} for command {}", e.getLocalizedMessage(),
+                    runDockerCommand.toCMD(), e);
+        }
+    }
+
+    private void startCallbackListener(String userName, ReuploadKeyCallbackDTO dto) {
+        folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
+                configuration.getKeyLoaderPollTimeout(),
+                new ReuploadKeyCallbackHandler(selfService, ApiCallbacks.REUPLOAD_KEY_URI,
+                        userName, dto));
+    }
+
+    @Override
+    public String getResourceType() {
+        return Directories.EDGE_LOG_DIRECTORY;
+    }
+
+    private RunDockerCommand buildRunDockerCommand(ReuploadKeyCallbackDTO callbackDto, DockerAction action) {
+        return new RunDockerCommand()
+                .withInteractive()
+                .withName(getContainerName(callbackDto))
+                .withVolumeForRootKeys(configuration.getKeyDirectory())
+                .withVolumeForResponse(configuration.getKeyLoaderDirectory())
+                .withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
+                .withResource(callbackDto.getResource().getResourceType().toString())
+                .withRequestId(callbackDto.getId())
+                .withConfKeyName(configuration.getAdminKey())
+                .withImage(configuration.getEdgeImage())
+                .withAction(action);
+    }
+
+    private ReuploadKeyCallbackDTO buildCallbackDTO(ResourceData resource, String uuid, ReuploadKeyDTO dto) {
+        return new ReuploadKeyCallbackDTO()
+                .withId(uuid)
+                .withEdgeUserName(dto.getEdgeUserName())
+                .withServiceBaseName(dto.getServiceBaseName())
+                .withConfOsFamily(dto.getConfOsFamily())
+                .withResourceId(resource.getResourceId())
+                .withResource(resource);
+    }
+
+    private ReuploadKeyCallbackDTO buildDockerCommandDTO(ReuploadKeyCallbackDTO dto) {
+        return new ReuploadKeyCallbackDTO()
+                .withEdgeUserName(dto.getEdgeUserName())
+                .withServiceBaseName(dto.getServiceBaseName())
+                .withConfOsFamily(dto.getConfOsFamily())
+                .withResourceId(dto.getResourceId());
+    }
+
+    private String getContainerName(ReuploadKeyCallbackDTO callbackDto) {
+        return nameContainer(callbackDto.getEdgeUserName(), REUPLOAD_KEY_ACTION,
+                callbackDto.getResource().getResourceType().toString(),
+                callbackDto.getResource().getResourceId());
+    }
+
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java
new file mode 100644
index 0000000..7754286
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java
@@ -0,0 +1,135 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.commands.CommandBuilder;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.ICommandExecutor;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.folderlistener.FolderListenerExecutor;
+import com.epam.datalab.backendapi.core.response.handlers.ProjectCallbackHandler;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.ResourceBaseDTO;
+import com.epam.datalab.dto.aws.edge.EdgeInfoAws;
+import com.epam.datalab.dto.azure.edge.EdgeInfoAzure;
+import com.epam.datalab.dto.gcp.edge.EdgeInfoGcp;
+import com.epam.datalab.dto.project.ProjectActionDTO;
+import com.epam.datalab.dto.project.ProjectCreateDTO;
+import com.epam.datalab.rest.client.RESTService;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Objects;
+
+@Slf4j
+public class ProjectServiceImpl implements ProjectService {
+    private static final String PROJECT_IMAGE = "docker.datalab-project";
+    private static final String EDGE_IMAGE = "docker.datalab-edge";
+    private static final String CALLBACK_URI = "/api/project/status";
+
+    protected final RESTService selfService;
+    private final ProvisioningServiceApplicationConfiguration configuration;
+    private final FolderListenerExecutor folderListenerExecutor;
+    private final ICommandExecutor commandExecutor;
+    private final CommandBuilder commandBuilder;
+
+    @Inject
+    public ProjectServiceImpl(RESTService selfService, ProvisioningServiceApplicationConfiguration configuration,
+                              FolderListenerExecutor folderListenerExecutor, ICommandExecutor commandExecutor, CommandBuilder commandBuilder) {
+        this.selfService = selfService;
+        this.configuration = configuration;
+        this.folderListenerExecutor = folderListenerExecutor;
+        this.commandExecutor = commandExecutor;
+        this.commandBuilder = commandBuilder;
+    }
+
+    @Override
+    public String create(UserInfo userInfo, ProjectCreateDTO dto) {
+        return executeDocker(userInfo, dto, DockerAction.CREATE, dto.getName(), "project", PROJECT_IMAGE,
+                dto.getEndpoint());
+    }
+
+    @Override
+    public String terminate(UserInfo userInfo, ProjectActionDTO dto) {
+        return executeDocker(userInfo, dto, DockerAction.TERMINATE, dto.getName(), "project", PROJECT_IMAGE,
+                dto.getEndpoint());
+    }
+
+    @Override
+    public String start(UserInfo userInfo, ProjectActionDTO dto) {
+        return executeDocker(userInfo, dto, DockerAction.START, dto.getName(), "edge", EDGE_IMAGE, dto.getEndpoint());
+    }
+
+    @Override
+    public String stop(UserInfo userInfo, ProjectActionDTO dto) {
+        return executeDocker(userInfo, dto, DockerAction.STOP, dto.getName(), "edge", EDGE_IMAGE, dto.getEndpoint());
+    }
+
+    private String executeDocker(UserInfo userInfo, ResourceBaseDTO dto, DockerAction action, String projectName,
+                                 String resourceType, String image, String endpoint) {
+        String uuid = DockerCommands.generateUUID();
+
+        folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
+                configuration.getKeyLoaderPollTimeout(),
+                new ProjectCallbackHandler(selfService, userInfo.getName(), uuid,
+                        action, CALLBACK_URI, projectName, getEdgeClass(), endpoint));
+
+        RunDockerCommand runDockerCommand = new RunDockerCommand()
+                .withInteractive()
+                .withName(String.join("_", userInfo.getSimpleName(), projectName, resourceType, action.toString(),
+                        Long.toString(System.currentTimeMillis())))
+                .withVolumeForRootKeys(configuration.getKeyDirectory())
+                .withVolumeForResponse(configuration.getKeyLoaderDirectory())
+                .withVolumeForLog(configuration.getDockerLogDirectory(), resourceType)
+                .withResource(resourceType)
+                .withRequestId(uuid)
+                .withConfKeyName(configuration.getAdminKey())
+                .withImage(image)
+                .withAction(action);
+        if (configuration.getCloudProvider() == CloudProvider.AZURE &&
+                Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
+                !configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
+            runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
+        }
+
+        try {
+            commandExecutor.executeAsync(userInfo.getName(), uuid, commandBuilder.buildCommand(runDockerCommand, dto));
+        } catch (JsonProcessingException e) {
+            log.error("Something went wrong. Reason {}", e.getMessage(), e);
+        }
+        return uuid;
+    }
+
+    private <T> Class<T> getEdgeClass() {
+        if (configuration.getCloudProvider() == CloudProvider.AWS) {
+            return (Class<T>) EdgeInfoAws.class;
+        } else if (configuration.getCloudProvider() == CloudProvider.AZURE) {
+            return (Class<T>) EdgeInfoAzure.class;
+        } else if (configuration.getCloudProvider() == CloudProvider.GCP) {
+            return (Class<T>) EdgeInfoGcp.class;
+        }
+        throw new IllegalArgumentException();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/RestoreCallbackHandlerServiceImpl.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/RestoreCallbackHandlerServiceImpl.java
new file mode 100644
index 0000000..4e21d0d
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/RestoreCallbackHandlerServiceImpl.java
@@ -0,0 +1,58 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.core.response.folderlistener.FolderListenerExecutor;
+import com.epam.datalab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
+import com.epam.datalab.backendapi.service.RestoreCallbackHandlerService;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import io.dropwizard.lifecycle.Managed;
+import io.dropwizard.util.Duration;
+import lombok.extern.slf4j.Slf4j;
+
+@Singleton
+@Slf4j
+public class RestoreCallbackHandlerServiceImpl implements Managed, RestoreCallbackHandlerService {
+
+    @Inject
+    private CallbackHandlerDao callbackHandlerDao;
+    @Inject
+    private FolderListenerExecutor folderListenerExecutor;
+
+    @Override
+    public void start() {
+        restore();
+    }
+
+    @Override
+    public void stop() {
+        log.info("RestoreCallbackHandlerServiceImpl stopped");
+    }
+
+    public void restore() {
+        log.info("Restoring callback handlers");
+        callbackHandlerDao.findAll().forEach(persistentFileHandler ->
+                folderListenerExecutor.start(persistentFileHandler.getDirectory(),
+                        Duration.milliseconds(persistentFileHandler.getTimeout()),
+                        persistentFileHandler.getHandler()));
+        log.info("Successfully restored file handlers");
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/SparkClusterService.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/SparkClusterService.java
new file mode 100644
index 0000000..62ae5b1
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/SparkClusterService.java
@@ -0,0 +1,156 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.handlers.ComputationalCallbackHandler;
+import com.epam.datalab.backendapi.core.response.handlers.ComputationalConfigure;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.epam.datalab.dto.computational.ComputationalClusterConfigDTO;
+import com.epam.datalab.dto.computational.ComputationalStartDTO;
+import com.epam.datalab.dto.computational.ComputationalStopDTO;
+import com.epam.datalab.dto.computational.ComputationalTerminateDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import java.util.Objects;
+
+import static com.epam.datalab.backendapi.core.commands.DockerAction.CREATE;
+import static com.epam.datalab.backendapi.core.commands.DockerAction.RECONFIGURE_SPARK;
+import static com.epam.datalab.backendapi.core.commands.DockerAction.START;
+import static com.epam.datalab.backendapi.core.commands.DockerAction.STOP;
+import static com.epam.datalab.backendapi.core.commands.DockerAction.TERMINATE;
+
+@Singleton
+public class SparkClusterService extends DockerService implements DockerCommands {
+
+    private static final DataEngineType SPARK_ENGINE = DataEngineType.SPARK_STANDALONE;
+
+    @Inject
+    private ComputationalConfigure computationalConfigure;
+
+    public String create(UserInfo ui, ComputationalBase<?> dto) {
+        return action(ui, dto, CREATE);
+    }
+
+    public String terminate(UserInfo ui, ComputationalTerminateDTO dto) {
+        return action(ui, dto, TERMINATE);
+    }
+
+    public String stop(UserInfo ui, ComputationalStopDTO dto) {
+        return action(ui, dto, STOP);
+    }
+
+    public String start(UserInfo ui, ComputationalStartDTO dto) {
+        return action(ui, dto, START);
+    }
+
+    public String updateConfig(UserInfo ui, ComputationalClusterConfigDTO clusterConfigDTO) {
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallback(RECONFIGURE_SPARK, uuid, clusterConfigDTO));
+        runReconfigureSparkDockerCommand(ui, clusterConfigDTO, uuid);
+        return uuid;
+    }
+
+    private void runReconfigureSparkDockerCommand(UserInfo ui, ComputationalClusterConfigDTO clusterConfigDTO,
+                                                  String uuid) {
+        try {
+            final RunDockerCommand runDockerCommand = new RunDockerCommand()
+                    .withInteractive()
+                    .withName(nameContainer(clusterConfigDTO.getEdgeUserName(), RECONFIGURE_SPARK,
+                            clusterConfigDTO.getExploratoryName(),
+                            clusterConfigDTO.getComputationalName()))
+                    .withVolumeForRootKeys(configuration.getKeyDirectory())
+                    .withVolumeForResponse(configuration.getImagesDirectory())
+                    .withVolumeForLog(configuration.getDockerLogDirectory(), SPARK_ENGINE.getName())
+                    .withResource(SPARK_ENGINE.getName())
+                    .withRequestId(uuid)
+                    .withConfKeyName(configuration.getAdminKey())
+                    .withImage(DataEngineType.getDockerImageName(SPARK_ENGINE))
+                    .withAction(RECONFIGURE_SPARK);
+            if (configuration.getCloudProvider() == CloudProvider.AZURE &&
+                    Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
+                    !configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
+                runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
+            }
+
+            commandExecutor.executeAsync(ui.getName(), uuid, commandBuilder.buildCommand(runDockerCommand,
+                    clusterConfigDTO));
+        } catch (JsonProcessingException e) {
+            throw new DatalabException("Could not" + RECONFIGURE_SPARK.toString() + "computational resources cluster", e);
+        }
+    }
+
+    private String action(UserInfo ui, ComputationalBase<?> dto, DockerAction action) {
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallback(action, uuid, dto));
+        try {
+            final RunDockerCommand runDockerCommand = new RunDockerCommand()
+                    .withInteractive()
+                    .withName(nameContainer(dto.getEdgeUserName(), action, dto.getExploratoryName(),
+                            dto.getComputationalName()))
+                    .withVolumeForRootKeys(configuration.getKeyDirectory())
+                    .withVolumeForResponse(configuration.getImagesDirectory())
+                    .withVolumeForLog(configuration.getDockerLogDirectory(), SPARK_ENGINE.getName())
+                    .withResource(SPARK_ENGINE.getName())
+                    .withRequestId(uuid)
+                    .withConfKeyName(configuration.getAdminKey())
+                    .withImage(DataEngineType.getDockerImageName(SPARK_ENGINE))
+                    .withAction(action);
+            if (configuration.getCloudProvider() == CloudProvider.AZURE &&
+                    Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
+                    !configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
+                runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
+            }
+
+            commandExecutor.executeAsync(ui.getName(), uuid, commandBuilder.buildCommand(runDockerCommand, dto));
+        } catch (JsonProcessingException e) {
+            throw new DatalabException("Could not" + action.toString() + "computational resources cluster", e);
+        }
+
+        return uuid;
+    }
+
+    private FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, ComputationalBase<?> dto) {
+        return new ComputationalCallbackHandler(computationalConfigure, selfService, action, uuid, dto);
+    }
+
+    private String nameContainer(String user, DockerAction action, String exploratoryName, String name) {
+        return nameContainer(user, action.toString(), "computational", exploratoryName, name);
+    }
+
+    @Override
+    public String getResourceType() {
+        return Directories.DATA_ENGINE_LOG_DIRECTORY;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/aws/BucketServiceAwsImpl.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/aws/BucketServiceAwsImpl.java
new file mode 100644
index 0000000..8fec02a
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/aws/BucketServiceAwsImpl.java
@@ -0,0 +1,153 @@
+/*
+ * 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.datalab.backendapi.service.impl.aws;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.BucketService;
+import com.epam.datalab.dto.bucket.BucketDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import lombok.extern.slf4j.Slf4j;
+import software.amazon.awssdk.core.sync.RequestBody;
+import software.amazon.awssdk.core.sync.ResponseTransformer;
+import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.services.s3.model.Delete;
+import software.amazon.awssdk.services.s3.model.DeleteObjectsRequest;
+import software.amazon.awssdk.services.s3.model.GetObjectRequest;
+import software.amazon.awssdk.services.s3.model.ListObjectsRequest;
+import software.amazon.awssdk.services.s3.model.ObjectIdentifier;
+import software.amazon.awssdk.services.s3.model.PutObjectRequest;
+import software.amazon.awssdk.services.s3.model.S3Object;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class BucketServiceAwsImpl implements BucketService {
+
+    @Override
+    public List<BucketDTO> getObjects(String bucket) {
+        try (S3Client s3 = S3Client.create()) {
+            ListObjectsRequest getRequest = ListObjectsRequest
+                    .builder()
+                    .bucket(bucket)
+                    .build();
+
+            return s3.listObjects(getRequest).contents()
+                    .stream()
+                    .map(o -> toBucketDTO(bucket, o))
+                    .collect(Collectors.toList());
+        } catch (Exception e) {
+            log.error("Cannot retrieve objects from bucket {}. Reason: {}", bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot retrieve objects from bucket %s. Reason: %s", bucket, e.getMessage()));
+        }
+    }
+
+    @Override
+    public void uploadObject(String bucket, String object, InputStream stream, String contentType, long fileSize) {
+        log.info("Uploading file {} to bucket {}", object, bucket);
+        try (S3Client s3 = S3Client.create()) {
+            PutObjectRequest uploadRequest = PutObjectRequest
+                    .builder()
+                    .bucket(bucket)
+                    .key(object)
+                    .contentType(contentType)
+                    .build();
+            s3.putObject(uploadRequest, RequestBody.fromInputStream(stream, fileSize));
+        } catch (Exception e) {
+            log.error("Cannot upload object {} to bucket {}. Reason: {}", object, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot upload object %s to bucket %s. Reason: %s", object, bucket, e.getMessage()));
+        }
+        log.info("Finished uploading file {} to bucket {}", object, bucket);
+    }
+
+    @Override
+    public void uploadFolder(UserInfo userInfo, String bucket, String folder) {
+        log.info("Uploading folder {} to bucket {}", folder, bucket);
+        try (S3Client s3 = S3Client.create()) {
+            PutObjectRequest uploadRequest = PutObjectRequest
+                    .builder()
+                    .bucket(bucket)
+                    .key(folder)
+                    .build();
+            s3.putObject(uploadRequest, RequestBody.empty());
+        } catch (Exception e) {
+            log.error("Cannot upload folder {} to bucket {}. Reason: {}", folder, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot upload folder %s to bucket %s. Reason: %s", folder, bucket, e.getMessage()));
+        }
+        log.info("Finished uploading folder {} to bucket {}", folder, bucket);
+    }
+
+    @Override
+    public void downloadObject(String bucket, String object, HttpServletResponse resp) {
+        log.info("Downloading file {} from bucket {}", object, bucket);
+        try (ServletOutputStream outputStream = resp.getOutputStream(); S3Client s3 = S3Client.create()) {
+            GetObjectRequest downloadRequest = GetObjectRequest
+                    .builder()
+                    .bucket(bucket)
+                    .key(object)
+                    .build();
+            s3.getObject(downloadRequest, ResponseTransformer.toOutputStream(outputStream));
+        } catch (Exception e) {
+            log.error("Cannot download object {} from bucket {}. Reason: {}", object, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot download object %s from bucket %s. Reason: %s", object, bucket, e.getMessage()));
+        }
+        log.info("Finished downloading file {} from bucket {}", object, bucket);
+    }
+
+    @Override
+    public void deleteObjects(String bucket, List<String> objects) {
+        try (S3Client s3 = S3Client.create()) {
+            List<ObjectIdentifier> objectsToDelete = objects
+                    .stream()
+                    .map(o -> ObjectIdentifier.builder()
+                            .key(o)
+                            .build())
+                    .collect(Collectors.toList());
+
+            DeleteObjectsRequest deleteObjectsRequests = DeleteObjectsRequest.builder()
+                    .bucket(bucket)
+                    .delete(Delete.builder()
+                            .objects(objectsToDelete)
+                            .build())
+                    .build();
+
+            s3.deleteObjects(deleteObjectsRequests);
+        } catch (Exception e) {
+            log.error("Cannot delete objects {} from bucket {}. Reason: {}", objects, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot delete objects %s from bucket %s. Reason: %s", objects, bucket, e.getMessage()));
+        }
+    }
+
+    private BucketDTO toBucketDTO(String bucket, S3Object s3Object) {
+        Date date = Date.from(s3Object.lastModified());
+        SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
+        return BucketDTO.builder()
+                .bucket(bucket)
+                .object(s3Object.key())
+                .size(String.valueOf(s3Object.size()))
+                .lastModifiedDate(formatter.format(date))
+                .build();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/azure/BucketServiceAzureImpl.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/azure/BucketServiceAzureImpl.java
new file mode 100644
index 0000000..192f7b0
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/azure/BucketServiceAzureImpl.java
@@ -0,0 +1,177 @@
+/*
+ * 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.datalab.backendapi.service.impl.azure;
+
+import com.azure.identity.ClientSecretCredentialBuilder;
+import com.azure.storage.blob.BlobClient;
+import com.azure.storage.blob.BlobContainerClient;
+import com.azure.storage.blob.BlobServiceClient;
+import com.azure.storage.blob.BlobServiceClientBuilder;
+import com.azure.storage.blob.models.BlobItem;
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.service.BucketService;
+import com.epam.datalab.dto.bucket.BucketDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.model.azure.AzureAuthFile;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class BucketServiceAzureImpl implements BucketService {
+    private final AzureAuthFile azureAuthFile;
+
+    @Inject
+    public BucketServiceAzureImpl(ProvisioningServiceApplicationConfiguration configuration) throws Exception {
+        azureAuthFile = getAzureAuthFile(configuration);
+    }
+
+    @Override
+    public List<BucketDTO> getObjects(String bucket) {
+        try {
+            AzureStorageAccount account = getAzureStorageAccount(bucket);
+            BlobServiceClient blobServiceClient = getBlobServiceClient(account.getStorageAccount());
+            BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient(account.getContainer());
+            return blobContainerClient.listBlobs()
+                    .stream()
+                    .map(blob -> toBucketDTO(account.getContainer(), blob))
+                    .collect(Collectors.toList());
+        } catch (Exception e) {
+            log.error("Cannot retrieve objects from bucket {}. Reason: {}", bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot retrieve objects from bucket %s. Reason: %s", bucket, e.getMessage()));
+        }
+    }
+
+    @Override
+    public void uploadObject(String bucket, String object, InputStream stream, String contentType, long fileSize) {
+        log.info("Uploading file {} to bucket {}", object, bucket);
+        try {
+            AzureStorageAccount account = getAzureStorageAccount(bucket);
+            BlobServiceClient blobServiceClient = getBlobServiceClient(account.getStorageAccount());
+            BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient(account.getContainer());
+            BlobClient blobClient = blobContainerClient.getBlobClient(object);
+            blobClient.upload(stream, fileSize);
+        } catch (Exception e) {
+            log.error("Cannot upload object {} to bucket {}. Reason: {}", object, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot upload object %s to bucket %s. Reason: %s", object, bucket, e.getMessage()));
+        }
+        log.info("Finished uploading file {} to bucket {}", object, bucket);
+    }
+
+    @Override
+    public void uploadFolder(UserInfo userInfo, String bucket, String folder) {
+        // Azure doesn't support this feature
+    }
+
+    @Override
+    public void downloadObject(String bucket, String object, HttpServletResponse resp) {
+        log.info("Downloading file {} from bucket {}", object, bucket);
+        try (ServletOutputStream outputStream = resp.getOutputStream()) {
+            AzureStorageAccount account = getAzureStorageAccount(bucket);
+            BlobServiceClient blobServiceClient = getBlobServiceClient(account.getStorageAccount());
+            BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient(account.getContainer());
+            BlobClient blobClient = blobContainerClient.getBlobClient(object);
+            blobClient.download(outputStream);
+        } catch (Exception e) {
+            log.error("Cannot download object {} from bucket {}. Reason: {}", object, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot download object %s from bucket %s. Reason: %s", object, bucket, e.getMessage()));
+        }
+        log.info("Finished downloading file {} from bucket {}", object, bucket);
+    }
+
+    @Override
+    public void deleteObjects(String bucket, List<String> objects) {
+        try {
+            AzureStorageAccount account = getAzureStorageAccount(bucket);
+            BlobServiceClient blobServiceClient = getBlobServiceClient(account.getStorageAccount());
+            BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient(account.getContainer());
+            objects.forEach(object -> blobContainerClient.getBlobClient(object).delete());
+        } catch (Exception e) {
+            log.error("Cannot delete objects {} from bucket {}. Reason: {}", objects, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot delete objects %s from bucket %s. Reason: %s", objects, bucket, e.getMessage()));
+        }
+    }
+
+    private BucketDTO toBucketDTO(String bucket, BlobItem blob) {
+        String lastModifiedDate = blob.getProperties().getLastModified().format(DateTimeFormatter.ofPattern(DATE_FORMAT));
+        return BucketDTO.builder()
+                .bucket(bucket)
+                .object(blob.getName())
+                .lastModifiedDate(lastModifiedDate)
+                .size(String.valueOf(blob.getProperties().getContentLength()))
+                .build();
+    }
+
+    private AzureAuthFile getAzureAuthFile(ProvisioningServiceApplicationConfiguration configuration) throws Exception {
+        final String authFile = configuration.getCloudConfiguration().getAzureAuthFile();
+        Path path = Paths.get(authFile);
+        if (path.toFile().exists()) {
+            try {
+                return new ObjectMapper().readValue(path.toFile(), AzureAuthFile.class);
+            } catch (IOException e) {
+                log.error("Cannot parse azure auth file {}", authFile, e);
+                throw new IOException("Cannot parse azure auth file " + authFile);
+            } catch (Exception e) {
+                log.error("Something went wrong while parsing azure auth file {}", authFile, e);
+                throw new Exception("Something went wrong while parsing azure auth file " + authFile);
+            }
+        } else {
+            throw new FileNotFoundException("Cannot find azure auth file for path" + authFile);
+        }
+    }
+
+    private BlobServiceClient getBlobServiceClient(String storageAccount) {
+        final String endpoint = String.format("https://%s.blob.core.windows.net", storageAccount);
+        return new BlobServiceClientBuilder()
+                .endpoint(endpoint)
+                .credential(new ClientSecretCredentialBuilder()
+                        .clientId(azureAuthFile.getClientId())
+                        .clientSecret(azureAuthFile.getClientSecret())
+                        .tenantId(azureAuthFile.getTenantId())
+                        .build())
+                .buildClient();
+    }
+
+    private AzureStorageAccount getAzureStorageAccount(String bucket) {
+        String[] a = bucket.split("\\.");
+        return new AzureStorageAccount(a[0], a[1]);
+    }
+
+    @Getter
+    @AllArgsConstructor
+    private static class AzureStorageAccount {
+        private final String storageAccount;
+        private final String container;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/gcp/BucketServiceGcpImpl.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/gcp/BucketServiceGcpImpl.java
new file mode 100644
index 0000000..9ea6628
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/gcp/BucketServiceGcpImpl.java
@@ -0,0 +1,132 @@
+/*
+ * 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.datalab.backendapi.service.impl.gcp;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.BucketService;
+import com.epam.datalab.dto.bucket.BucketDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.cloud.storage.Blob;
+import com.google.cloud.storage.BlobId;
+import com.google.cloud.storage.BlobInfo;
+import com.google.cloud.storage.Bucket;
+import com.google.cloud.storage.Storage;
+import com.google.cloud.storage.StorageOptions;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+@Slf4j
+public class BucketServiceGcpImpl implements BucketService {
+
+    @Override
+    public List<BucketDTO> getObjects(String bucket) {
+        try {
+            Storage storage = StorageOptions.getDefaultInstance().getService();
+            Bucket gcpBucket = storage.get(bucket);
+            return StreamSupport.stream(gcpBucket.list().getValues().spliterator(), false)
+                    .map(this::toBucketDTO)
+                    .collect(Collectors.toList());
+        } catch (Exception e) {
+            log.error("Cannot retrieve objects from bucket {}. Reason: {}", bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot retrieve objects from bucket %s. Reason: %s", bucket, e.getMessage()));
+        }
+    }
+
+    @Override
+    public void uploadObject(String bucket, String object, InputStream stream, String contentType, long fileSize) {
+        log.info("Uploading file {} to bucket {}", object, bucket);
+        try {
+            Storage storage = StorageOptions.getDefaultInstance().getService();
+            BlobId blobId = BlobId.of(bucket, object);
+            BlobInfo blobInfo = BlobInfo.newBuilder(blobId)
+                    .setContentType(contentType)
+                    .build();
+            storage.create(blobInfo, stream);
+        } catch (Exception e) {
+            log.error("Cannot upload object {} to bucket {}. Reason: {}", object, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot upload object %s to bucket %s. Reason: %s", object, bucket, e.getMessage()));
+        }
+        log.info("Finished uploading file {} to bucket {}", object, bucket);
+    }
+
+    @Override
+    public void uploadFolder(UserInfo userInfo, String bucket, String folder) {
+        log.info("Uploading file {} to bucket {}", folder, bucket);
+        try {
+            Storage storage = StorageOptions.getDefaultInstance().getService();
+            BlobId blobId = BlobId.of(bucket, folder);
+            BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build();
+            storage.create(blobInfo);
+        } catch (Exception e) {
+            log.error("Cannot upload folder {} to bucket {}. Reason: {}", folder, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot upload folder %s to bucket %s. Reason: %s", folder, bucket, e.getMessage()));
+        }
+        log.info("Finished uploading folder {} to bucket {}", folder, bucket);
+    }
+
+    @Override
+    public void downloadObject(String bucket, String object, HttpServletResponse resp) {
+        log.info("Downloading file {} from bucket {}", object, bucket);
+        try (ServletOutputStream outputStream = resp.getOutputStream()) {
+            Storage storage = StorageOptions.getDefaultInstance().getService();
+            Blob blob = storage.get(BlobId.of(bucket, object));
+            blob.downloadTo(outputStream);
+            log.info("Finished downloading file {} from bucket {}", object, bucket);
+        } catch (Exception e) {
+            log.error("Cannot download object {} from bucket {}. Reason: {}", object, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot download object %s from bucket %s. Reason: %s", object, bucket, e.getMessage()));
+        }
+        log.info("Finished downloading file {} from bucket {}", object, bucket);
+    }
+
+    @Override
+    public void deleteObjects(String bucket, List<String> objects) {
+        try {
+            Storage storage = StorageOptions.getDefaultInstance().getService();
+            List<BlobId> blobIds = objects
+                    .stream()
+                    .map(o -> BlobId.of(bucket, o))
+                    .collect(Collectors.toList());
+            storage.delete(blobIds);
+        } catch (Exception e) {
+            log.error("Cannot delete objects {} from bucket {}. Reason: {}", objects, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot delete objects %s from bucket %s. Reason: %s", objects, bucket, e.getMessage()));
+        }
+    }
+
+    private BucketDTO toBucketDTO(BlobInfo blobInfo) {
+        Date date = new Date(blobInfo.getUpdateTime());
+        SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
+        return BucketDTO.builder()
+                .bucket(blobInfo.getBucket())
+                .object(blobInfo.getName())
+                .size(String.valueOf(blobInfo.getSize()))
+                .lastModifiedDate(formatter.format(date))
+                .build();
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/validation/ProvisioningServiceCloudConfigurationSequenceProvider.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/validation/ProvisioningServiceCloudConfigurationSequenceProvider.java
new file mode 100644
index 0000000..435c5b4
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/validation/ProvisioningServiceCloudConfigurationSequenceProvider.java
@@ -0,0 +1,28 @@
+/*
+ * 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.datalab.backendapi.validation;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.validation.CloudConfigurationSequenceProvider;
+
+public class ProvisioningServiceCloudConfigurationSequenceProvider
+        extends CloudConfigurationSequenceProvider<ProvisioningServiceApplicationConfiguration> {
+
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/process/ProcessConveyor.java b/services/provisioning-service/src/main/java/com/epam/datalab/process/ProcessConveyor.java
new file mode 100644
index 0000000..0d741f4
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/process/ProcessConveyor.java
@@ -0,0 +1,59 @@
+/*
+ * 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.datalab.process;
+
+import com.aegisql.conveyor.AssemblingConveyor;
+import com.aegisql.conveyor.BuildingSite;
+import com.aegisql.conveyor.cart.Cart;
+import com.aegisql.conveyor.cart.FutureCart;
+import com.epam.datalab.process.model.ProcessId;
+import com.epam.datalab.process.model.ProcessInfo;
+import com.epam.datalab.process.model.ProcessStep;
+
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+
+public class ProcessConveyor extends AssemblingConveyor<ProcessId, ProcessStep, ProcessInfo> {
+
+    public ProcessConveyor() {
+        super();
+        this.setName("ProcessConveyor");
+        this.setIdleHeartBeat(1, TimeUnit.SECONDS);
+        this.enablePostponeExpiration(true);
+        this.enablePostponeExpirationOnTimeout(true);
+        this.setDefaultCartConsumer((l, v, b) -> {
+            LOG.warn("default processor for {} {} {}", l, v, b.get());
+            if (v instanceof FutureCart) {
+                @SuppressWarnings("rawtypes")
+                FutureCart fc = (FutureCart) v;
+                fc.get().cancel(true);
+            }
+        });
+        this.setResultConsumer(bin -> LOG.debug("process finished: {}", bin));
+    }
+
+    public Supplier<? extends ProcessInfo> getInfoSupplier(ProcessId id) {
+        BuildingSite<ProcessId, ProcessStep, Cart<ProcessId, ?, ProcessStep>, ? extends ProcessInfo> bs = this.collector.get(id);
+        if (bs == null) {
+            return () -> null;
+        } else {
+            return bs.getProductSupplier();
+        }
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/process/builder/ProcessInfoBuilder.java b/services/provisioning-service/src/main/java/com/epam/datalab/process/builder/ProcessInfoBuilder.java
new file mode 100644
index 0000000..cfa285f
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/process/builder/ProcessInfoBuilder.java
@@ -0,0 +1,288 @@
+/*
+ * 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.datalab.process.builder;
+
+import com.aegisql.conveyor.Expireable;
+import com.aegisql.conveyor.Testing;
+import com.aegisql.conveyor.TimeoutAction;
+import com.epam.datalab.process.model.DatalabProcess;
+import com.epam.datalab.process.model.ProcessId;
+import com.epam.datalab.process.model.ProcessInfo;
+import com.epam.datalab.process.model.ProcessStatus;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import static com.epam.datalab.process.model.ProcessStatus.CREATED;
+import static com.epam.datalab.process.model.ProcessStatus.FAILED;
+import static com.epam.datalab.process.model.ProcessStatus.FINISHED;
+import static com.epam.datalab.process.model.ProcessStatus.KILLED;
+import static com.epam.datalab.process.model.ProcessStatus.LAUNCHING;
+import static com.epam.datalab.process.model.ProcessStatus.REJECTED;
+import static com.epam.datalab.process.model.ProcessStatus.RUNNING;
+import static com.epam.datalab.process.model.ProcessStatus.SCHEDULED;
+import static com.epam.datalab.process.model.ProcessStatus.STOPPED;
+import static com.epam.datalab.process.model.ProcessStatus.TIMEOUT;
+
+@Slf4j
+public class ProcessInfoBuilder implements Supplier<ProcessInfo>, Testing, TimeoutAction, Expireable {
+
+    private static Function<Process, Integer> pidSupplier = null;
+    private final ProcessId processId;
+    private final long startTimeStamp = System.currentTimeMillis();
+    private final StringBuilder stdOut = new StringBuilder();
+    private final StringBuilder stdErr = new StringBuilder();
+    private ProcessStatus status = CREATED;
+    private int exitCode = -1;
+    private String[] command = new String[]{"N/A"};
+    private Collection<ProcessInfo> rejected = null;
+    private int pid = -1;
+    private boolean finished = false;
+    private boolean stdOutClosed = false;
+    private boolean stdErrClosed = false;
+    private Process p = null;
+    private CompletableFuture<ProcessInfo> future;
+    private long expirationTime;
+
+    public ProcessInfoBuilder(ProcessId processId, long ttl) {
+        this.processId = processId;
+        this.expirationTime = System.currentTimeMillis() + ttl;
+    }
+
+    public static void schedule(ProcessInfoBuilder b, String[] command) {
+        b.status = SCHEDULED;
+        b.command = command;
+    }
+
+    public static void start(ProcessInfoBuilder b, String[] command) {
+        if (b.status == CREATED) {
+            b.status = LAUNCHING;
+            b.command = command;
+            b.launch();
+        } else {
+            if (b.rejected == null) {
+                b.rejected = new LinkedList<>();
+            }
+            long timeStamp = System.currentTimeMillis();
+            b.rejected.add(new ProcessInfo(
+                    b.processId,
+                    REJECTED,
+                    command,
+                    "",
+                    "rejected duplicated command",
+                    REJECTED.ordinal(),
+                    timeStamp,
+                    timeStamp, null, b.pid));
+        }
+    }
+
+    public static void failed(ProcessInfoBuilder b, Object dummy) {
+        b.status = FAILED;
+        b.setReady();
+    }
+
+    public static void stop(ProcessInfoBuilder b, Object dummy) {
+        if (b.p != null) {
+            b.p.destroy();
+        }
+        if (b.status != LAUNCHING && b.status != RUNNING) {
+            b.setReady();
+        }
+        b.status = STOPPED;
+    }
+
+    public static void kill(ProcessInfoBuilder b, Object dummy) {
+        if (b.p != null) {
+            b.p.destroyForcibly();
+        }
+        if (b.status != LAUNCHING && b.status != RUNNING) {
+            b.setReady();
+        }
+        b.status = KILLED;
+    }
+
+    public static void finish(ProcessInfoBuilder b, Integer exitCode) {
+        if (b.status != STOPPED && b.status != KILLED && b.status != TIMEOUT) {
+            b.status = FINISHED;
+        }
+        b.exitCode = exitCode;
+        b.finished = true;
+    }
+
+    public static void stdOut(ProcessInfoBuilder b, Object msg) {
+        if (msg == null) {
+            b.stdOutClosed = true;
+        } else {
+            b.stdOut.append(msg).append("\n");
+        }
+    }
+
+    public static void stdErr(ProcessInfoBuilder b, Object msg) {
+        if (msg == null) {
+            b.stdErrClosed = true;
+        } else {
+            b.stdErr.append(msg).append("\n");
+        }
+    }
+
+    public static void future(ProcessInfoBuilder b, CompletableFuture<ProcessInfo> future) {
+        if (b.future == null) {
+            b.future = future;
+        } else {
+            future.cancel(true);
+        }
+    }
+
+    public static int getPid(Process process) {
+        try {
+            if (pidSupplier == null) {
+                Class<?> cProcessImpl = process.getClass();
+                final Field fPid = cProcessImpl.getDeclaredField("pid");
+                log.debug("PID field found");
+                if (!fPid.isAccessible()) {
+                    fPid.setAccessible(true);
+                }
+                pidSupplier = p -> {
+                    try {
+                        return fPid.getInt(p);
+                    } catch (IllegalAccessException e) {
+                        log.error("Unable to access PID. {}", e.getMessage(), e);
+                        return -1;
+                    }
+                };
+            }
+            return pidSupplier.apply(process);
+        } catch (NoSuchFieldException e) {
+            log.debug("PID field not found", e);
+            pidSupplier = p -> -1;
+            return -1;
+        }
+    }
+
+    private void launch() {
+        DatalabProcess.getInstance().getUsersExecutorService(processId.getUser()).submit(() -> {
+            status = SCHEDULED;
+            DatalabProcess.getInstance().getExecutorService().execute(() -> {
+                try {
+                    p = new ProcessBuilder(command).start();
+                    pid = getPid(p);
+                    InputStream stdOutStream = p.getInputStream();
+                    DatalabProcess.getInstance().getExecutorService().execute(() -> print(stdOutStream));
+                    InputStream stdErrStream = p.getErrorStream();
+                    DatalabProcess.getInstance().getExecutorService().execute(() -> printError(stdErrStream));
+                    status = RUNNING;
+                    int exit = p.waitFor();
+                    DatalabProcess.getInstance().finish(processId, exit);
+                } catch (IOException e) {
+                    DatalabProcess.getInstance().toStdErr(processId, "Command launch failed. " + get().getCommand(), e);
+                    DatalabProcess.getInstance().failed(processId);
+                } catch (InterruptedException e) {
+                    DatalabProcess.getInstance().toStdErr(processId, "Command interrupted. " + get().getCommand(), e);
+                    DatalabProcess.getInstance().failed(processId);
+                    Thread.currentThread().interrupt();
+                }
+            });
+            try {
+                future.get();
+            } catch (Exception e) {
+                log.error("Exception occurred during getting future result: {}", e.getMessage(), e);
+            }
+        });
+    }
+
+    private void printError(InputStream stdErrStream) {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(stdErrStream));
+        String line;
+        try {
+            while ((line = reader.readLine()) != null) {
+                DatalabProcess.getInstance().toStdErr(processId, line);
+            }
+            DatalabProcess.getInstance().toStdErr(processId, null);
+        } catch (IOException e) {
+            DatalabProcess.getInstance().toStdErr(processId, "Failed process STDERR reader", e);
+            DatalabProcess.getInstance().failed(processId);
+        }
+    }
+
+    private void print(InputStream stdOutStream) {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(stdOutStream));
+        String line;
+        try {
+            while ((line = reader.readLine()) != null) {
+                DatalabProcess.getInstance().toStdOut(processId, line);
+            }
+            DatalabProcess.getInstance().toStdOut(processId, null);
+        } catch (IOException e) {
+            DatalabProcess.getInstance().toStdErr(processId, "Failed process STDOUT reader", e);
+            DatalabProcess.getInstance().failed(processId);
+        }
+    }
+
+    @Override
+    public ProcessInfo get() {
+        return new ProcessInfo(
+                processId,
+                status,
+                command,
+                stdOut.toString(),
+                stdErr.toString(),
+                exitCode,
+                startTimeStamp, System.currentTimeMillis(), rejected, pid);
+    }
+
+    @Override
+    public boolean test() {
+        return finished && stdOutClosed && stdErrClosed;
+    }
+
+    private void setReady() {
+        finished = true;
+        stdOutClosed = true;
+        stdErrClosed = true;
+    }
+
+    @Override
+    public void onTimeout() {
+        if (status != TIMEOUT) {
+            log.debug("Stopping on timeout ...");
+            stop(this, "STOP");
+            status = TIMEOUT;
+            expirationTime += 60_000;
+        } else {
+            log.debug("Killing on timeout ...");
+            kill(this, "KILL");
+            status = TIMEOUT;
+            setReady();
+        }
+    }
+
+    @Override
+    public long getExpirationTime() {
+        return expirationTime;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/process/exception/DatalabProcessException.java b/services/provisioning-service/src/main/java/com/epam/datalab/process/exception/DatalabProcessException.java
new file mode 100644
index 0000000..05a5ede
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/process/exception/DatalabProcessException.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.process.exception;
+
+public class DatalabProcessException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public DatalabProcessException() {
+    }
+
+    public DatalabProcessException(String message) {
+        super(message);
+    }
+
+    public DatalabProcessException(String message, Exception cause) {
+        super(message, cause);
+    }
+
+    public DatalabProcessException(Exception cause) {
+        super(cause);
+    }
+
+    public DatalabProcessException(String message, Exception cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/process/model/DatalabProcess.java b/services/provisioning-service/src/main/java/com/epam/datalab/process/model/DatalabProcess.java
new file mode 100644
index 0000000..9722ab6
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/process/model/DatalabProcess.java
@@ -0,0 +1,167 @@
+/*
+ * 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.datalab.process.model;
+
+import com.epam.datalab.process.ProcessConveyor;
+import com.epam.datalab.process.builder.ProcessInfoBuilder;
+import com.epam.datalab.util.SecurityUtils;
+import io.dropwizard.util.Duration;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class DatalabProcess {
+
+    private final static DatalabProcess INSTANCE = new DatalabProcess();
+    private final ProcessConveyor processConveyor;
+    private ExecutorService executorService = Executors.newFixedThreadPool(50 * 3);
+    private Map<String, ExecutorService> perUserService = new ConcurrentHashMap<>();
+    private int userMaxparallelism = 5;
+    private long expirationTime = TimeUnit.HOURS.toMillis(3);
+
+    private DatalabProcess() {
+        this.processConveyor = new ProcessConveyor();
+    }
+
+    public static DatalabProcess getInstance() {
+        return INSTANCE;
+    }
+
+    public ExecutorService getExecutorService() {
+        return executorService;
+    }
+
+    public void setMaxProcessesPerBox(int parallelism) {
+        this.executorService.shutdown();
+        this.executorService = Executors.newFixedThreadPool(3 * parallelism);
+    }
+
+    public void setMaxProcessesPerUser(int parallelism) {
+        this.userMaxparallelism = parallelism;
+        this.perUserService.forEach((k, e) -> e.shutdown());
+        this.perUserService = new ConcurrentHashMap<>();
+    }
+
+    public ExecutorService getUsersExecutorService(String user) {
+        perUserService.putIfAbsent(user, Executors.newFixedThreadPool(userMaxparallelism));
+        return perUserService.get(user);
+    }
+
+    public CompletableFuture<ProcessInfo> start(ProcessId id, String... command) {
+        log.debug("Run OS command for user {} with UUID {}: {}", id.getUser(), id.getCommand(),
+                SecurityUtils.hideCreds(command));
+        CompletableFuture<ProcessInfo> future = processConveyor.createBuildFuture(id, () -> new ProcessInfoBuilder(id,
+                expirationTime));
+        processConveyor.add(id, future, ProcessStep.FUTURE);
+        processConveyor.add(id, command, ProcessStep.START);
+        return future;
+    }
+
+    public CompletableFuture<ProcessInfo> start(String username, String uniqDescriptor, String... command) {
+        return start(new ProcessId(username, uniqDescriptor), command);
+    }
+
+    public CompletableFuture<ProcessInfo> start(String username, String... command) {
+        return start(new ProcessId(username, String.join(" ", command)), command);
+    }
+
+
+    public CompletableFuture<Boolean> stop(ProcessId id) {
+        return processConveyor.add(id, "STOP", ProcessStep.STOP);
+    }
+
+    public CompletableFuture<Boolean> stop(String username, String command) {
+        return stop(new ProcessId(username, command));
+    }
+
+    public CompletableFuture<Boolean> kill(ProcessId id) {
+        return processConveyor.add(id, "KILL", ProcessStep.KILL);
+    }
+
+    public CompletableFuture<Boolean> kill(String username, String command) {
+        return kill(new ProcessId(username, command));
+    }
+
+    public CompletableFuture<Boolean> failed(ProcessId id) {
+        return processConveyor.add(id, "FAILED", ProcessStep.FAILED);
+    }
+
+    public CompletableFuture<Boolean> finish(ProcessId id, Integer exitStatus) {
+        return processConveyor.add(id, exitStatus, ProcessStep.FINISH);
+    }
+
+    public CompletableFuture<Boolean> toStdOut(ProcessId id, String msg) {
+        return processConveyor.add(id, msg, ProcessStep.STD_OUT);
+    }
+
+    public CompletableFuture<Boolean> toStdErr(ProcessId id, String msg) {
+        return processConveyor.add(id, msg, ProcessStep.STD_ERR);
+    }
+
+    public CompletableFuture<Boolean> toStdErr(ProcessId id, String msg, Exception err) {
+        StringWriter sw = new StringWriter();
+        sw.append(msg);
+        sw.append("\n");
+        PrintWriter pw = new PrintWriter(sw);
+        err.printStackTrace(pw);
+        return processConveyor.add(id, sw.toString(), ProcessStep.STD_ERR);
+    }
+
+    public Collection<ProcessId> getActiveProcesses() {
+        Collection<ProcessId> pList = new ArrayList<>();
+        processConveyor.forEachKeyAndBuilder((k, b) -> pList.add(k));
+        return pList;
+    }
+
+    public Collection<ProcessId> getActiveProcesses(String username) {
+        return getActiveProcesses()
+                .stream()
+                .filter(id -> id.getUser().equals(username))
+                .collect(Collectors.toList());
+    }
+
+    public Supplier<? extends ProcessInfo> getProcessInfoSupplier(ProcessId id) {
+        return processConveyor.getInfoSupplier(id);
+    }
+
+    public Supplier<? extends ProcessInfo> getProcessInfoSupplier(String username, String command) {
+        return getProcessInfoSupplier(new ProcessId(username, command));
+    }
+
+    public void setProcessTimeout(long time, TimeUnit unit) {
+        this.expirationTime = unit.toMillis(time);
+    }
+
+    public void setProcessTimeout(Duration duration) {
+        this.expirationTime = duration.toMilliseconds();
+    }
+
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/process/model/ProcessId.java b/services/provisioning-service/src/main/java/com/epam/datalab/process/model/ProcessId.java
new file mode 100644
index 0000000..4b33cd0
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/process/model/ProcessId.java
@@ -0,0 +1,70 @@
+/*
+ * 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.datalab.process.model;
+
+public class ProcessId {
+
+    private final String user;
+    private final String command;
+
+    public ProcessId(String user, String command) {
+        this.user = user;
+        this.command = command;
+    }
+
+    public String getCommand() {
+        return command;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        ProcessId processId = (ProcessId) o;
+
+        if (user != null ? !user.equals(processId.user) : processId.user != null) {
+            return false;
+        }
+        return command != null ? command.equals(processId.command) : processId.command == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = user != null ? user.hashCode() : 0;
+        result = 31 * result + (command != null ? command.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "ProcessId{" +
+                "user='" + user + '\'' +
+                ", command='" + command + '\'' +
+                '}';
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/process/model/ProcessInfo.java b/services/provisioning-service/src/main/java/com/epam/datalab/process/model/ProcessInfo.java
new file mode 100644
index 0000000..1f812e8
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/process/model/ProcessInfo.java
@@ -0,0 +1,120 @@
+/*
+ * 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.datalab.process.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+public class ProcessInfo {
+
+    private final ProcessId id;
+    private final String[] command;
+    private final ProcessStatus status;
+    private final String stdOut;
+    private final String stdErr;
+    private final int exitCode;
+    private final long startTimeStamp;
+    private final long infoTimeStamp;
+    private final int pid;
+
+    private final Collection<ProcessInfo> rejectedCommands;
+
+    public ProcessInfo(ProcessId id, ProcessStatus status, String[] command, String stdOut, String stdErr, int exitCode,
+                       long startTimeStamp, long infoTimeStamp, Collection<ProcessInfo> rejected, int pid) {
+        this.id = id;
+        this.status = status;
+        this.command = command;
+        this.stdOut = stdOut;
+        this.stdErr = stdErr;
+        this.exitCode = exitCode;
+        this.startTimeStamp = startTimeStamp;
+        this.infoTimeStamp = infoTimeStamp;
+        this.pid = pid;
+
+        if (rejected != null && rejected.size() > 0) {
+            Collection<ProcessInfo> r = new ArrayList<>();
+            for (ProcessInfo info : rejected) {
+                if (info != null) {
+                    r.add(info);
+                }
+            }
+            this.rejectedCommands = Collections.unmodifiableCollection(r);
+        } else {
+            this.rejectedCommands = null;
+        }
+
+    }
+
+    public String getCommand() {
+        return String.join(" ", command);
+    }
+
+    public ProcessStatus getStatus() {
+        return status;
+    }
+
+    public String getStdOut() {
+        return stdOut;
+    }
+
+    public String getStdErr() {
+        return stdErr;
+    }
+
+    public int getExitCode() {
+        return exitCode;
+    }
+
+    public long getStartTimeStamp() {
+        return startTimeStamp;
+    }
+
+    public long getInfoTimeStamp() {
+        return infoTimeStamp;
+    }
+
+    public ProcessId getId() {
+        return id;
+    }
+
+    public int getPid() {
+        return pid;
+    }
+
+    public Collection<ProcessInfo> getRejectedCommands() {
+        return Collections.unmodifiableCollection(rejectedCommands);
+    }
+
+    @Override
+    public String toString() {
+        return "ProcessInfo{" +
+                "id='" + id + '\'' +
+                ", command='" + getCommand() + '\'' +
+                ", pid=" + pid +
+                ", status=" + status +
+                ", stdOut='" + stdOut + '\'' +
+                ", stdErr='" + stdErr + '\'' +
+                ", exitCode=" + exitCode +
+                ", startTimeStamp=" + startTimeStamp +
+                ", infoTimeStamp=" + infoTimeStamp +
+                ", rejectedCommands=" + rejectedCommands +
+                '}';
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/process/model/ProcessStatus.java b/services/provisioning-service/src/main/java/com/epam/datalab/process/model/ProcessStatus.java
new file mode 100644
index 0000000..dee1b6b
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/process/model/ProcessStatus.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.datalab.process.model;
+
+public enum ProcessStatus {
+    CREATED,
+    LAUNCHING,
+    RUNNING,
+    STOPPED,
+    KILLED,
+    TIMEOUT,
+    FINISHED,
+    REJECTED,
+    FAILED,
+    SCHEDULED
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/process/model/ProcessStep.java b/services/provisioning-service/src/main/java/com/epam/datalab/process/model/ProcessStep.java
new file mode 100644
index 0000000..fa9111c
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/process/model/ProcessStep.java
@@ -0,0 +1,47 @@
+/*
+ * 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.datalab.process.model;
+
+import com.aegisql.conveyor.SmartLabel;
+import com.epam.datalab.process.builder.ProcessInfoBuilder;
+
+import java.util.function.BiConsumer;
+
+public enum ProcessStep implements SmartLabel<ProcessInfoBuilder> {
+    START(ProcessInfoBuilder::start),
+    STOP(ProcessInfoBuilder::stop),
+    KILL(ProcessInfoBuilder::kill),
+    FINISH(ProcessInfoBuilder::finish),
+    STD_OUT(ProcessInfoBuilder::stdOut),
+    STD_ERR(ProcessInfoBuilder::stdErr),
+    FAILED(ProcessInfoBuilder::failed),
+    FUTURE(ProcessInfoBuilder::future),
+    ;
+    private BiConsumer<ProcessInfoBuilder, Object> consumer;
+
+    @SuppressWarnings("unchecked")
+    <T> ProcessStep(BiConsumer<ProcessInfoBuilder, T> consumer) {
+        this.consumer = (BiConsumer<ProcessInfoBuilder, Object>) consumer;
+    }
+
+    @Override
+    public BiConsumer<ProcessInfoBuilder, Object> get() {
+        return consumer;
+    }
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/DropwizardBearerTokenFilterImpl.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/DropwizardBearerTokenFilterImpl.java
deleted file mode 100644
index fc2659c..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/DropwizardBearerTokenFilterImpl.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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;
-
-import org.keycloak.adapters.AdapterDeploymentContext;
-import org.keycloak.adapters.KeycloakDeployment;
-import org.keycloak.adapters.NodesRegistrationManagement;
-import org.keycloak.jaxrs.JaxrsBearerTokenFilterImpl;
-
-import javax.annotation.Priority;
-import javax.ws.rs.Priorities;
-import javax.ws.rs.container.PreMatching;
-
-@PreMatching
-@Priority(Priorities.AUTHENTICATION)
-public class DropwizardBearerTokenFilterImpl extends JaxrsBearerTokenFilterImpl {
-
-	public DropwizardBearerTokenFilterImpl(KeycloakDeployment keycloakDeployment) {
-		deploymentContext = new AdapterDeploymentContext(keycloakDeployment);
-		nodesRegistrationManagement = new NodesRegistrationManagement();
-	}
-}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplication.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplication.java
deleted file mode 100644
index fbb5f5a..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplication.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.DirectoriesCreator;
-import com.epam.dlab.backendapi.core.DockerWarmuper;
-import com.epam.dlab.backendapi.core.response.handlers.ComputationalConfigure;
-import com.epam.dlab.backendapi.modules.CloudModuleConfigurator;
-import com.epam.dlab.backendapi.modules.ModuleFactory;
-import com.epam.dlab.backendapi.resources.BackupResource;
-import com.epam.dlab.backendapi.resources.BucketResource;
-import com.epam.dlab.backendapi.resources.CallbackHandlerResource;
-import com.epam.dlab.backendapi.resources.DockerResource;
-import com.epam.dlab.backendapi.resources.GitExploratoryResource;
-import com.epam.dlab.backendapi.resources.ImageResource;
-import com.epam.dlab.backendapi.resources.InfrastructureResource;
-import com.epam.dlab.backendapi.resources.LibraryResource;
-import com.epam.dlab.backendapi.resources.ProjectResource;
-import com.epam.dlab.backendapi.resources.ProvisioningHealthCheckResource;
-import com.epam.dlab.backendapi.resources.base.KeyResource;
-import com.epam.dlab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
-import com.epam.dlab.cloud.CloudModule;
-import com.epam.dlab.process.model.DlabProcess;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.mappers.JsonProcessingExceptionMapper;
-import com.epam.dlab.rest.mappers.RuntimeExceptionMapper;
-import com.epam.dlab.util.ServiceUtils;
-import com.fasterxml.jackson.databind.InjectableValues;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import de.ahus1.keycloak.dropwizard.AbstractKeycloakAuthenticator;
-import de.ahus1.keycloak.dropwizard.KeycloakBundle;
-import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
-import de.thomaskrille.dropwizard_template_config.TemplateConfigBundle;
-import de.thomaskrille.dropwizard_template_config.TemplateConfigBundleConfiguration;
-import io.dropwizard.Application;
-import io.dropwizard.auth.Authenticator;
-import io.dropwizard.auth.Authorizer;
-import io.dropwizard.forms.MultiPartBundle;
-import io.dropwizard.jersey.setup.JerseyEnvironment;
-import io.dropwizard.setup.Bootstrap;
-import io.dropwizard.setup.Environment;
-import org.keycloak.KeycloakSecurityContext;
-
-import javax.servlet.http.HttpServletRequest;
-import java.security.Principal;
-
-public class ProvisioningServiceApplication extends Application<ProvisioningServiceApplicationConfiguration> {
-
-	public static void main(String[] args) throws Exception {
-		if (ServiceUtils.printAppVersion(ProvisioningServiceApplication.class, args)) {
-			return;
-		}
-		new ProvisioningServiceApplication().run(args);
-	}
-
-	@Override
-	public void initialize(Bootstrap<ProvisioningServiceApplicationConfiguration> bootstrap) {
-        bootstrap.addBundle(new MultiPartBundle());
-        bootstrap.addBundle(new TemplateConfigBundle(
-                new TemplateConfigBundleConfiguration().fileIncludePath(ServiceUtils.getConfPath())
-        ));
-        bootstrap.addBundle(new KeycloakBundle<ProvisioningServiceApplicationConfiguration>() {
-            @Override
-            protected KeycloakConfiguration getKeycloakConfiguration(ProvisioningServiceApplicationConfiguration configuration) {
-                return configuration.getKeycloakConfiguration();
-            }
-
-            @Override
-			protected Class<? extends Principal> getUserClass() {
-				return UserInfo.class;
-			}
-
-			@Override
-			protected Authorizer createAuthorizer() {
-				return (Authorizer<UserInfo>) (principal, role) -> principal.getRoles().contains(role);
-			}
-
-			@Override
-			protected Authenticator createAuthenticator(KeycloakConfiguration configuration) {
-				class KeycloakAuthenticator extends AbstractKeycloakAuthenticator<UserInfo> {
-
-					private KeycloakAuthenticator(KeycloakConfiguration keycloakConfiguration) {
-						super(keycloakConfiguration);
-					}
-
-					@Override
-					protected UserInfo prepareAuthentication(KeycloakSecurityContext keycloakSecurityContext,
-															 HttpServletRequest httpServletRequest,
-															 KeycloakConfiguration keycloakConfiguration) {
-						return new UserInfo(keycloakSecurityContext.getToken().getPreferredUsername(),
-								keycloakSecurityContext.getIdTokenString());
-					}
-				}
-				return new KeycloakAuthenticator(configuration);
-			}
-		});
-	}
-
-	@Override
-	public void run(ProvisioningServiceApplicationConfiguration configuration, Environment environment) {
-		DlabProcess.getInstance().setProcessTimeout(configuration.getProcessTimeout());
-		DlabProcess.getInstance().setMaxProcessesPerBox(configuration.getProcessMaxThreadsPerJvm());
-		DlabProcess.getInstance().setMaxProcessesPerUser(configuration.getProcessMaxThreadsPerUser());
-
-		CloudModule cloudModule = CloudModuleConfigurator.getCloudModule(configuration);
-		Injector injector = Guice.createInjector(ModuleFactory.getModule(configuration, environment), cloudModule);
-		cloudModule.init(environment, injector);
-
-
-		final ObjectMapper mapper = injector.getInstance(ObjectMapper.class);
-		final InjectableValues.Std injectableValues = new InjectableValues.Std();
-		injectableValues.addValue(RESTService.class, injector.getInstance(RESTService.class));
-		injectableValues.addValue(ComputationalConfigure.class, injector.getInstance(ComputationalConfigure.class));
-		mapper.setInjectableValues(injectableValues);
-
-		environment.lifecycle().manage(injector.getInstance(DirectoriesCreator.class));
-		if (configuration.isHandlersPersistenceEnabled()) {
-			environment.lifecycle().manage(injector.getInstance(RestoreCallbackHandlerServiceImpl.class));
-		}
-		environment.lifecycle().manage(injector.getInstance(DockerWarmuper.class));
-
-
-		JerseyEnvironment jersey = environment.jersey();
-		jersey.register(configuration.getCloudProvider());
-		jersey.register(new RuntimeExceptionMapper());
-		jersey.register(new JsonProcessingExceptionMapper());
-
-		jersey.register(injector.getInstance(DockerResource.class));
-		jersey.register(injector.getInstance(GitExploratoryResource.class));
-		jersey.register(injector.getInstance(LibraryResource.class));
-		jersey.register(injector.getInstance(InfrastructureResource.class));
-		jersey.register(injector.getInstance(ImageResource.class));
-		jersey.register(injector.getInstance(BackupResource.class));
-		jersey.register(injector.getInstance(KeyResource.class));
-		jersey.register(injector.getInstance(CallbackHandlerResource.class));
-		jersey.register(injector.getInstance(ProjectResource.class));
-		jersey.register(injector.getInstance(ProvisioningHealthCheckResource.class));
-		environment.jersey().register(injector.getInstance(BucketResource.class));
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplicationConfiguration.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplicationConfiguration.java
deleted file mode 100644
index 4edc8af..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplicationConfiguration.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * 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;
-
-import com.epam.dlab.ServiceConfiguration;
-import com.epam.dlab.backendapi.conf.CloudConfiguration;
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.validation.ProvisioningServiceCloudConfigurationSequenceProvider;
-import com.epam.dlab.validation.AwsValidation;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
-import io.dropwizard.util.Duration;
-import org.hibernate.validator.constraints.NotEmpty;
-import org.hibernate.validator.group.GroupSequenceProvider;
-
-@GroupSequenceProvider(ProvisioningServiceCloudConfigurationSequenceProvider.class)
-public class ProvisioningServiceApplicationConfiguration extends ServiceConfiguration implements Directories {
-
-	@NotEmpty
-	@JsonProperty
-	private String keyDirectory;
-
-	@NotEmpty
-	@JsonProperty
-	private String responseDirectory;
-
-	@NotEmpty
-	@JsonProperty
-	private String dockerLogDirectory;
-
-	@NotEmpty
-	@JsonProperty
-	private String handlerDirectory;
-
-	@JsonProperty
-	private Duration warmupPollTimeout;
-
-	@JsonProperty
-	private Duration resourceStatusPollTimeout = Duration.minutes(3);
-
-	@JsonProperty
-	private Duration keyLoaderPollTimeout = Duration.minutes(2);
-
-	@JsonProperty
-	private Duration requestEnvStatusTimeout = Duration.seconds(30);
-
-	@NotEmpty
-	@JsonProperty
-	private String adminKey;
-
-	@NotEmpty
-	@JsonProperty
-	private String edgeImage;
-
-	@JsonProperty
-	private Duration fileLengthCheckDelay = Duration.seconds(3);
-
-	@NotEmpty(groups = AwsValidation.class)
-	@JsonProperty
-	private String emrEC2RoleDefault;
-
-	@NotEmpty(groups = AwsValidation.class)
-	@JsonProperty
-	private String emrServiceRoleDefault;
-
-	@JsonProperty
-	private int processMaxThreadsPerJvm = 50;
-
-	@JsonProperty
-	private int processMaxThreadsPerUser = 5;
-
-	@JsonProperty
-	private Duration processTimeout = Duration.hours(3);
-	@JsonProperty
-	private String backupScriptPath;
-	@JsonProperty
-	private String backupDirectory;
-	@JsonProperty
-	private boolean handlersPersistenceEnabled;
-
-	private KeycloakConfiguration keycloakConfiguration = new KeycloakConfiguration();
-
-	@JsonProperty("cloudProperties")
-	private CloudConfiguration cloudConfiguration;
-
-	public boolean isHandlersPersistenceEnabled() {
-		return handlersPersistenceEnabled;
-	}
-
-	public String getKeyDirectory() {
-		return keyDirectory;
-	}
-
-	public Duration getWarmupPollTimeout() {
-		return warmupPollTimeout;
-	}
-
-	public Duration getResourceStatusPollTimeout() {
-		return resourceStatusPollTimeout;
-	}
-
-	public Duration getKeyLoaderPollTimeout() {
-		return keyLoaderPollTimeout;
-	}
-
-	/**
-	 * Return the timeout for the check the status of environment resources.
-	 */
-	public Duration getRequestEnvStatusTimeout() {
-		return requestEnvStatusTimeout;
-	}
-
-	public String getAdminKey() {
-		return adminKey;
-	}
-
-	public String getEdgeImage() {
-		return edgeImage;
-	}
-
-	public Duration getFileLengthCheckDelay() {
-		return fileLengthCheckDelay;
-	}
-
-	public String getEmrEC2RoleDefault() {
-		return emrEC2RoleDefault;
-	}
-
-	public String getEmrServiceRoleDefault() {
-		return emrServiceRoleDefault;
-	}
-
-	public String getWarmupDirectory() {
-		return responseDirectory + WARMUP_DIRECTORY;
-	}
-
-	public String getImagesDirectory() {
-		return responseDirectory + IMAGES_DIRECTORY;
-	}
-
-	public String getKeyLoaderDirectory() {
-		return responseDirectory + KEY_LOADER_DIRECTORY;
-	}
-
-	public String getDockerLogDirectory() {
-		return dockerLogDirectory;
-	}
-
-	public int getProcessMaxThreadsPerJvm() {
-		return processMaxThreadsPerJvm;
-	}
-
-	public int getProcessMaxThreadsPerUser() {
-		return processMaxThreadsPerUser;
-	}
-
-	public Duration getProcessTimeout() {
-		return processTimeout;
-	}
-
-	public String getBackupScriptPath() {
-		return backupScriptPath;
-	}
-
-	public String getBackupDirectory() {
-		return backupDirectory;
-	}
-
-	public String getHandlerDirectory() {
-		return handlerDirectory;
-	}
-
-	public KeycloakConfiguration getKeycloakConfiguration() {
-		return keycloakConfiguration;
-	}
-
-	public CloudConfiguration getCloudConfiguration() {
-		return cloudConfiguration;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/conf/CloudConfiguration.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/conf/CloudConfiguration.java
deleted file mode 100644
index c25624c..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/conf/CloudConfiguration.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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.conf;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-@Data
-public class CloudConfiguration {
-
-	private final String os;
-	private final String serviceBaseName;
-	private final String edgeInstanceSize;
-	private final String subnetId;
-	private final String region;
-	private final String zone;
-	private final String confTagResourceId;
-	private final String securityGroupIds;
-	private final String ssnInstanceSize;
-	private final String notebookVpcId;
-	private final String notebookSubnetId;
-	private final String confKeyDir;
-	private final String vpcId;
-	private final String azureResourceGroupName;
-	private final String ssnStorageAccountTagName;
-	private final String sharedStorageAccountTagName;
-	private final String datalakeTagName;
-	private final String azureAuthFile;
-	private final String azureClientId;
-	private final String peeringId;
-	private final String gcpProjectId;
-	private final boolean imageEnabled;
-	@JsonProperty("ldap")
-	private final LdapConfig ldapConfig;
-	private final StepCerts stepCerts;
-	private final Keycloak keycloak;
-
-	@Data
-	public static class LdapConfig {
-		private final String host;
-		private final String dn;
-		private final String ou;
-		private final String user;
-		private final String password;
-	}
-
-	@Data
-	public static class StepCerts {
-		private final boolean enabled;
-		private final String rootCA;
-		private final String kid;
-		private final String kidPassword;
-		private final String caURL;
-	}
-
-	@Data
-	public static class Keycloak {
-		@JsonProperty("auth_server_url")
-		private final String authServerUrl;
-		@JsonProperty("realm_name")
-		private final String realmName;
-		private final String user;
-		@JsonProperty("user_password")
-		private final String userPassword;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/Constants.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/Constants.java
deleted file mode 100644
index 1c31d5a..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/Constants.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.core;
-
-public class Constants {
-
-    public static final String JSON_EXTENSION = ".json";
-    public static final String LOG_EXTENSION = ".log";
-
-    private Constants() {
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/Directories.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/Directories.java
deleted file mode 100644
index 1966f47..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/Directories.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.core;
-
-public interface Directories {
-    String WARMUP_DIRECTORY = "/result";
-    String IMAGES_DIRECTORY = "/result";
-    String KEY_LOADER_DIRECTORY = "/result";
-    String EDGE_LOG_DIRECTORY = "edge";
-    String NOTEBOOK_LOG_DIRECTORY = "notebook";
-    String DATA_ENGINE_LOG_DIRECTORY = "dataengine";
-    String DATA_ENGINE_SERVICE_LOG_DIRECTORY = "dataengine-service";
-    String IMAGE_LOG_DIRECTORY = "image";
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/DirectoriesCreator.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/DirectoriesCreator.java
deleted file mode 100644
index e8a17a0..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/DirectoriesCreator.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.core;
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import io.dropwizard.lifecycle.Managed;
-
-import java.io.File;
-
-@Singleton
-public class DirectoriesCreator implements Managed {
-	@Inject
-	private ProvisioningServiceApplicationConfiguration configuration;
-
-	@Override
-	public void start() throws Exception {
-		createDirectory(configuration.getWarmupDirectory());
-		createDirectory(configuration.getImagesDirectory());
-		createDirectory(configuration.getKeyLoaderDirectory());
-		createDirectory(configuration.getHandlerDirectory());
-	}
-
-	private boolean createDirectory(String directory) {
-		return new File(directory).mkdirs();
-	}
-
-	@Override
-	public void stop() throws Exception {
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/DockerWarmuper.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/DockerWarmuper.java
deleted file mode 100644
index 74cc4ad..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/DockerWarmuper.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * 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.core;
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.folderlistener.FolderListenerExecutor;
-import com.epam.dlab.dto.imagemetadata.ComputationalMetadataDTO;
-import com.epam.dlab.dto.imagemetadata.ExploratoryMetadataDTO;
-import com.epam.dlab.dto.imagemetadata.ImageMetadataDTO;
-import com.epam.dlab.dto.imagemetadata.ImageType;
-import com.epam.dlab.process.model.ProcessInfo;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import io.dropwizard.lifecycle.Managed;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
-
-
-@Singleton
-public class DockerWarmuper implements Managed, DockerCommands, MetadataHolder {
-	private static final Logger LOGGER = LoggerFactory.getLogger(DockerWarmuper.class);
-	public static final String EXPLORATORY_RESPONSE_MARKER = "exploratory_environment_shapes";
-
-	@Inject
-	private ProvisioningServiceApplicationConfiguration configuration;
-	@Inject
-	private FolderListenerExecutor folderListenerExecutor;
-	@Inject
-	private ICommandExecutor commandExecutor;
-	private Map<String, String> imageList = new ConcurrentHashMap<>();
-	private Set<ImageMetadataDTO> metadataDTOs = ConcurrentHashMap.newKeySet();
-
-
-	@Override
-	public void start() throws Exception {
-		LOGGER.debug("warming up docker");
-		final ProcessInfo processInfo = commandExecutor.executeSync("warmup", DockerCommands.generateUUID(),
-				GET_IMAGES);
-		List<String> images = Arrays.asList(processInfo.getStdOut().split("\n"));
-		for (String image : images) {
-			String uuid = UUID.randomUUID().toString();
-			LOGGER.debug("warming up image: {} with uid {}", image, uuid);
-			imageList.put(uuid, image);
-			folderListenerExecutor.start(configuration.getWarmupDirectory(),
-					configuration.getWarmupPollTimeout(),
-					getFileHandlerCallback(uuid));
-			String command = new RunDockerCommand()
-					.withVolumeForRootKeys(configuration.getKeyDirectory())
-					.withVolumeForResponse(configuration.getWarmupDirectory())
-					.withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
-					.withResource(getResourceType())
-					.withRequestId(uuid)
-					.withActionDescribe(image)
-					.toCMD();
-			commandExecutor.executeAsync("warmup", uuid, command);
-		}
-	}
-
-	public class DockerFileHandlerCallback implements FileHandlerCallback {
-		private final String uuid;
-
-		@JsonCreator
-		public DockerFileHandlerCallback(@JsonProperty("uuid") String uuid) {
-			this.uuid = uuid;
-		}
-
-		@Override
-		public String getUUID() {
-			return uuid;
-		}
-
-		@Override
-		public boolean checkUUID(String uuid) {
-			return this.uuid.equals(uuid);
-		}
-
-		@Override
-		public boolean handle(String fileName, byte[] content) {
-			String uuid = DockerCommands.extractUUID(fileName);
-			try {
-				LOGGER.debug("processing response file {} with content {}", fileName, new String(content));
-				addMetadata(content, uuid);
-			} catch (IOException e) {
-				LOGGER.error("processing response file {} fails", fileName, e);
-				return false;
-			}
-			return true;
-		}
-
-		@Override
-		public void handleError(String errorMessage) {
-			LOGGER.warn("docker warmupper returned no result: {}", errorMessage);
-		}
-
-		@Override
-		public String getUser() {
-			return "DLAB";
-		}
-	}
-
-	public DockerFileHandlerCallback getFileHandlerCallback(String uuid) {
-		return new DockerFileHandlerCallback(uuid);
-	}
-
-	private void addMetadata(byte[] content, String uuid) throws IOException {
-		final JsonNode jsonNode = MAPPER.readTree(content);
-		ImageMetadataDTO metadata;
-		if (jsonNode.has(EXPLORATORY_RESPONSE_MARKER)) {
-			metadata = MAPPER.readValue(content, ExploratoryMetadataDTO.class);
-			metadata.setImageType(ImageType.EXPLORATORY);
-		} else {
-			metadata = MAPPER.readValue(content, ComputationalMetadataDTO.class);
-			metadata.setImageType(ImageType.COMPUTATIONAL);
-		}
-		String image = imageList.get(uuid);
-		metadata.setImage(image);
-		LOGGER.debug("caching metadata for image {}: {}", image, metadata);
-		metadataDTOs.add(metadata);
-	}
-
-	@Override
-	public void stop() throws Exception {
-		//do nothing
-	}
-
-	public Map<String, String> getUuids() {
-		return Collections.unmodifiableMap(imageList);
-	}
-
-	public Set<ImageMetadataDTO> getMetadata(ImageType type) {
-		return metadataDTOs.stream().filter(m -> m.getImageType().equals(type))
-				.collect(Collectors.toSet());
-	}
-
-	@Override
-	public String getResourceType() {
-		return Directories.NOTEBOOK_LOG_DIRECTORY;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/FileHandlerCallback.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/FileHandlerCallback.java
deleted file mode 100644
index 7e7df74..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/FileHandlerCallback.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.core;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@class")
-public interface FileHandlerCallback {
-	String getUUID();
-
-	boolean checkUUID(String uuid);
-
-	boolean handle(String fileName, byte[] content) throws Exception;
-
-	void handleError(String errorMessage);
-
-	String getUser();
-
-	@JsonIgnore
-	default String getId() {
-		return this.getClass().getSimpleName() + "_" + getUUID();
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/MetadataHolder.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/MetadataHolder.java
deleted file mode 100644
index defbeaf..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/MetadataHolder.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.core;
-
-
-import com.epam.dlab.dto.imagemetadata.ImageMetadataDTO;
-import com.epam.dlab.dto.imagemetadata.ImageType;
-
-import java.util.Set;
-
-@FunctionalInterface
-public interface MetadataHolder {
-    Set<ImageMetadataDTO> getMetadata(ImageType metadataType);
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CmdCommand.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CmdCommand.java
deleted file mode 100644
index 0adfaa9..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CmdCommand.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.core.commands;
-
-@FunctionalInterface
-public interface CmdCommand {
-    String toCMD();
-}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandBuilder.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandBuilder.java
deleted file mode 100644
index f99eca4..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandBuilder.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * 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.core.commands;
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.conf.CloudConfiguration;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.ResourceBaseDTO;
-import com.epam.dlab.dto.aws.AwsCloudSettings;
-import com.epam.dlab.dto.azure.AzureCloudSettings;
-import com.epam.dlab.dto.base.CloudSettings;
-import com.epam.dlab.dto.gcp.GcpCloudSettings;
-import com.epam.dlab.util.JsonGenerator;
-import com.epam.dlab.util.SecurityUtils;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@Singleton
-public class CommandBuilder {
-
-	private final ProvisioningServiceApplicationConfiguration conf;
-
-	@Inject
-	public CommandBuilder(ProvisioningServiceApplicationConfiguration conf) {
-		this.conf = conf;
-	}
-
-	public String buildCommand(RunDockerCommand runDockerCommand, ResourceBaseDTO<?> resourceBaseDTO) throws JsonProcessingException {
-		StringBuilder builder = new StringBuilder();
-		if (resourceBaseDTO != null) {
-			builder.append("echo -e '");
-			try {
-				resourceBaseDTO.setCloudSettings(getCloudSettings(resourceBaseDTO.getCloudSettings()));
-				String str = JsonGenerator.generateJson(resourceBaseDTO);
-				log.info("Serialized DTO to: {}", SecurityUtils.hideCreds(str));
-				builder.append(str);
-			} catch (JsonProcessingException e) {
-				log.error("ERROR generating json from dockerRunParameters: {}", e.getMessage());
-				throw e;
-			}
-			builder.append('\'');
-			builder.append(" | ");
-		}
-		builder.append(runDockerCommand.toCMD());
-		return builder.toString();
-	}
-
-	private CloudSettings getCloudSettings(CloudSettings settings) {
-		final CloudProvider cloudProvider = conf.getCloudProvider();
-		final CloudConfiguration cloudConfiguration = conf.getCloudConfiguration();
-		final CloudConfiguration.LdapConfig ldapConfig = cloudConfiguration.getLdapConfig();
-		final CloudConfiguration.StepCerts stepCerts = cloudConfiguration.getStepCerts();
-		final CloudConfiguration.Keycloak keycloak = cloudConfiguration.getKeycloak();
-		if (cloudProvider == CloudProvider.AWS) {
-			return awsCloudSettings(settings, cloudConfiguration, ldapConfig, stepCerts, keycloak);
-		} else if (cloudProvider == CloudProvider.GCP) {
-			return gcpCloudSettings(settings, cloudConfiguration, ldapConfig, stepCerts, keycloak);
-		} else if (cloudProvider == CloudProvider.AZURE) {
-			return azureCloudSettings(settings, cloudConfiguration, ldapConfig, stepCerts, keycloak);
-		} else {
-			throw new UnsupportedOperationException("Unsupported cloud provider " + cloudProvider.getName());
-		}
-	}
-
-	private AzureCloudSettings azureCloudSettings(CloudSettings settings, CloudConfiguration cloudConfiguration,
-												  CloudConfiguration.LdapConfig ldapConfig,
-												  CloudConfiguration.StepCerts stepCerts,
-												  CloudConfiguration.Keycloak keycloak) {
-		return AzureCloudSettings.builder()
-				.azureRegion(cloudConfiguration.getRegion())
-				.azureResourceGroupName(cloudConfiguration.getAzureResourceGroupName())
-				.azureSecurityGroupName(cloudConfiguration.getSecurityGroupIds())
-				.ldapDn(ldapConfig.getDn())
-				.ldapHost(ldapConfig.getHost())
-				.ldapOu(ldapConfig.getOu())
-				.ldapUser(ldapConfig.getUser())
-				.ldapPassword(ldapConfig.getPassword())
-				.azureSubnetName(cloudConfiguration.getSubnetId())
-				.azureVpcName(cloudConfiguration.getVpcId())
-				.confKeyDir(cloudConfiguration.getConfKeyDir())
-				.azureIamUser(settings.getIamUser())
-				.sbn(cloudConfiguration.getServiceBaseName())
-				.os(cloudConfiguration.getOs())
-				.cloud(conf.getCloudProvider().getName())
-				.imageEnabled(String.valueOf(cloudConfiguration.isImageEnabled()))
-				.stepCertsEnabled(String.valueOf(stepCerts.isEnabled()))
-				.stepCertsRootCA(stepCerts.getRootCA())
-				.stepCertsKid(stepCerts.getKid())
-				.stepCertsKidPassword(stepCerts.getKidPassword())
-				.stepCertsCAURL(stepCerts.getCaURL())
-				.keycloakAuthServerUrl(keycloak.getAuthServerUrl())
-				.keycloakRealmName(keycloak.getRealmName())
-				.keycloakUser(keycloak.getUser())
-				.keycloakUserPassword(keycloak.getUserPassword())
-				.build();
-	}
-
-	private GcpCloudSettings gcpCloudSettings(CloudSettings settings, CloudConfiguration cloudConfiguration,
-											  CloudConfiguration.LdapConfig ldapConfig,
-											  CloudConfiguration.StepCerts stepCerts,
-											  CloudConfiguration.Keycloak keycloak) {
-		return GcpCloudSettings.builder()
-				.projectId(cloudConfiguration.getGcpProjectId())
-				.vpcName(cloudConfiguration.getVpcId())
-				.subnetName(cloudConfiguration.getSubnetId())
-				.zone(cloudConfiguration.getZone())
-				.region(cloudConfiguration.getRegion())
-				.ldapDn(ldapConfig.getDn())
-				.ldapHost(ldapConfig.getHost())
-				.ldapOu(ldapConfig.getOu())
-				.ldapUser(ldapConfig.getUser())
-				.ldapPassword(ldapConfig.getPassword())
-				.sbn(cloudConfiguration.getServiceBaseName())
-				.cloud(conf.getCloudProvider().getName())
-				.os(cloudConfiguration.getOs())
-				.confKeyDir(cloudConfiguration.getConfKeyDir())
-				.gcpIamUser(settings.getIamUser())
-				.imageEnabled(String.valueOf(cloudConfiguration.isImageEnabled()))
-				.stepCertsEnabled(String.valueOf(stepCerts.isEnabled()))
-				.stepCertsRootCA(stepCerts.getRootCA())
-				.stepCertsKid(stepCerts.getKid())
-				.stepCertsKidPassword(stepCerts.getKidPassword())
-				.stepCertsCAURL(stepCerts.getCaURL())
-				.keycloakAuthServerUrl(keycloak.getAuthServerUrl())
-				.keycloakRealmName(keycloak.getRealmName())
-				.keycloakUser(keycloak.getUser())
-				.keycloakUserPassword(keycloak.getUserPassword())
-				.build();
-	}
-
-	private AwsCloudSettings awsCloudSettings(CloudSettings settings, CloudConfiguration cloudConfiguration,
-											  CloudConfiguration.LdapConfig ldapConfig,
-											  CloudConfiguration.StepCerts stepCerts,
-											  CloudConfiguration.Keycloak keycloak) {
-		return AwsCloudSettings.builder()
-				.awsRegion(cloudConfiguration.getRegion())
-				.awsSecurityGroupIds(cloudConfiguration.getSecurityGroupIds())
-				.awsSubnetId(cloudConfiguration.getSubnetId())
-				.awsVpcId(cloudConfiguration.getVpcId())
-				.confTagResourceId(cloudConfiguration.getConfTagResourceId())
-				.awsNotebookSubnetId(cloudConfiguration.getNotebookSubnetId())
-				.awsNotebookVpcId(cloudConfiguration.getNotebookVpcId())
-				.awsIamUser(settings.getIamUser())
-				.zone(cloudConfiguration.getZone())
-				.ldapDn(ldapConfig.getDn())
-				.ldapHost(ldapConfig.getHost())
-				.ldapOu(ldapConfig.getOu())
-				.ldapUser(ldapConfig.getUser())
-				.ldapPassword(ldapConfig.getPassword())
-				.sbn(cloudConfiguration.getServiceBaseName())
-				.cloud(conf.getCloudProvider().getName())
-				.os(cloudConfiguration.getOs())
-				.confKeyDir(cloudConfiguration.getConfKeyDir())
-				.imageEnabled(String.valueOf(cloudConfiguration.isImageEnabled()))
-				.stepCertsEnabled(String.valueOf(stepCerts.isEnabled()))
-				.stepCertsRootCA(stepCerts.getRootCA())
-				.stepCertsKid(stepCerts.getKid())
-				.stepCertsKidPassword(stepCerts.getKidPassword())
-				.stepCertsCAURL(stepCerts.getCaURL())
-				.keycloakAuthServerUrl(keycloak.getAuthServerUrl())
-				.keycloakRealmName(keycloak.getRealmName())
-				.keycloakUser(keycloak.getUser())
-				.keycloakUserPassword(keycloak.getUserPassword())
-				.build();
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutor.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutor.java
deleted file mode 100644
index c74968f..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutor.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.core.commands;
-
-import com.epam.dlab.process.model.DlabProcess;
-import com.epam.dlab.process.model.ProcessId;
-import com.epam.dlab.process.model.ProcessInfo;
-import com.google.inject.Singleton;
-
-@Singleton
-public class CommandExecutor implements ICommandExecutor {
-
-	public ProcessInfo executeSync(final String username, final String uuid, String command) throws Exception {
-		return DlabProcess.getInstance().start(new ProcessId(username, uuid), "bash", "-c", command).get();
-
-	}
-
-	public void executeAsync(final String username, final String uuid, final String command) {
-		DlabProcess.getInstance().start(new ProcessId(username, uuid), "bash", "-c", command);
-	}
-}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMock.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMock.java
deleted file mode 100644
index 1cb6e43..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMock.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.core.commands;
-
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.process.builder.ProcessInfoBuilder;
-import com.epam.dlab.process.model.ProcessId;
-import com.epam.dlab.process.model.ProcessInfo;
-import com.google.common.collect.Lists;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-public class CommandExecutorMock implements ICommandExecutor {
-	private static final Logger LOGGER = LoggerFactory.getLogger(CommandExecutorMock.class);
-	public static final String DOCKER_DLAB_DATAENGINE = "docker.dlab-dataengine:latest";
-	public static final String DOCKER_DLAB_DATAENGINE_SERVICE = "docker.dlab-dataengine-service:latest";
-
-	private CommandExecutorMockAsync execAsync = null;
-	private CompletableFuture<Boolean> future;
-
-	private CloudProvider cloudProvider;
-
-	public CommandExecutorMock(CloudProvider cloudProvider) {
-		this.cloudProvider = cloudProvider;
-	}
-
-	/**
-	 * Return result of execution.
-	 *
-	 * @throws ExecutionException
-	 * @throws InterruptedException
-	 */
-	public boolean getResultSync() throws InterruptedException, ExecutionException {
-		return (future == null ? true : future.get());
-	}
-
-	/**
-	 * Return variables for substitution into Json response file.
-	 */
-	public Map<String, String> getVariables() {
-		return (execAsync == null ? null : execAsync.getParser().getVariables());
-	}
-
-	/**
-	 * Response file name.
-	 */
-	public String getResponseFileName() {
-		return (execAsync == null ? null : execAsync.getResponseFileName());
-	}
-
-	@Override
-	public ProcessInfo executeSync(String user, String uuid, String command) {
-		LOGGER.debug("Run OS command for user {} with UUID {}: {}", user, uuid, command);
-		ProcessInfoBuilder builder = new ProcessInfoBuilder(new ProcessId(user, command), 1000l);
-		if (command.startsWith("docker images |")) {
-			List<String> list = Lists.newArrayList(
-					"docker.dlab-deeplearning:latest",
-					"docker.dlab-jupyter:latest",
-					"docker.dlab-jupyterlab:latest",
-					"docker.dlab-superset:latest",
-					"docker.dlab-rstudio:latest",
-					"docker.dlab-tensor:latest",
-					"docker.dlab-zeppelin:latest",
-					"docker.dlab-tensor-rstudio:latest");
-
-			list.addAll(getComputationalDockerImage());
-
-			ProcessInfoBuilder.stdOut(builder, String.join("\n", list));
-		}
-		return builder.get();
-	}
-
-	@Override
-	public void executeAsync(String user, String uuid, String command) {
-		execAsync = new CommandExecutorMockAsync(user, uuid, command, cloudProvider);
-		future = CompletableFuture.supplyAsync(execAsync);
-	}
-
-	private List<String> getComputationalDockerImage() {
-		switch (cloudProvider) {
-			case AWS:
-				return Lists.newArrayList(DOCKER_DLAB_DATAENGINE_SERVICE, DOCKER_DLAB_DATAENGINE);
-			case AZURE:
-				return Lists.newArrayList(DOCKER_DLAB_DATAENGINE);
-			case GCP:
-				return Lists.newArrayList(DOCKER_DLAB_DATAENGINE_SERVICE, DOCKER_DLAB_DATAENGINE);
-			default:
-				throw new IllegalArgumentException("Unsupported cloud provider " + cloudProvider);
-		}
-	}
-
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMockAsync.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMockAsync.java
deleted file mode 100644
index 7ad66f8..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMockAsync.java
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * 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.core.commands;
-
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.exploratory.LibInstallDTO;
-import com.epam.dlab.dto.exploratory.LibStatus;
-import com.epam.dlab.dto.status.EnvResource;
-import com.epam.dlab.dto.status.EnvResourceList;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.util.SecurityUtils;
-import com.epam.dlab.util.ServiceUtils;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.Lists;
-import com.google.common.io.ByteStreams;
-import com.google.common.io.Files;
-import com.google.common.io.Resources;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.codec.Charsets;
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URL;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Supplier;
-
-@Slf4j
-public class CommandExecutorMockAsync implements Supplier<Boolean> {
-	private static final String JSON_FILE_ENDING = ".json";
-
-	private static final ObjectMapper MAPPER = new ObjectMapper()
-			.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true)
-			.setSerializationInclusion(JsonInclude.Include.NON_NULL);
-
-	private String user;
-	private String uuid;
-	private String command;
-
-	private CommandParserMock parser = new CommandParserMock();
-	private String responseFileName;
-
-	private CloudProvider cloudProvider;
-
-	public CommandExecutorMockAsync(String user, String uuid, String command, CloudProvider cloudProvider) {
-		this.user = user;
-		this.uuid = uuid;
-		this.command = command;
-		this.cloudProvider = cloudProvider;
-	}
-
-	@Override
-	public Boolean get() {
-		try {
-			run();
-		} catch (Exception e) {
-			log.error("Command with UUID {} fails: {}", uuid, e.getLocalizedMessage(), e);
-			return false;
-		}
-		return true;
-	}
-
-
-	/**
-	 * Return parser of command line.
-	 */
-	public CommandParserMock getParser() {
-		return parser;
-	}
-
-	/**
-	 * Return variables for substitution into Json response file.
-	 */
-	public Map<String, String> getVariables() {
-		return parser.getVariables();
-	}
-
-	/**
-	 * Response file name.
-	 */
-	public String getResponseFileName() {
-		return responseFileName;
-	}
-
-	public void run() {
-		log.debug("Run OS command for user {} with UUID {}: {}", user, uuid, SecurityUtils.hideCreds(command));
-
-		responseFileName = null;
-		parser = new CommandParserMock(command, uuid);
-		log.debug("Parser is {}", SecurityUtils.hideCreds(parser.toString()));
-		DockerAction action = DockerAction.of(parser.getAction());
-		log.debug("Action is {}", action);
-
-		if (parser.isDockerCommand()) {
-			if (action == null) {
-				throw new DlabException("Docker action not defined");
-			}
-
-			sleep(500);
-
-			try {
-				switch (action) {
-					case DESCRIBE:
-						describe();
-						break;
-					case CREATE:
-					case START:
-					case STOP:
-					case TERMINATE:
-					case GIT_CREDS:
-					case CREATE_IMAGE:
-					case RECONFIGURE_SPARK:
-					case CHECK_INACTIVITY:
-						action(user, action);
-						break;
-					case CONFIGURE:
-					case REUPLOAD_KEY:
-						sleep(1000);
-						action(user, action);
-						break;
-					case STATUS:
-						parser.getVariables().put("list_resources", getResponseStatus(true));
-						action(user, action);
-						break;
-					case LIB_LIST:
-						action(user, action);
-						copyFile(String.format("mock_response/%s/notebook_lib_list_pkgs.json",
-								cloudProvider.getName()),
-								String.join("_", "notebook", uuid, "all_pkgs") +
-										JSON_FILE_ENDING, parser.getResponsePath());
-						break;
-					case LIB_INSTALL:
-						parser.getVariables().put("lib_install", getResponseLibInstall(true));
-						action(user, action);
-						break;
-					default:
-						break;
-				}
-			} catch (Exception e) {
-				String msg = "Cannot execute command for user " + user + " with UUID " + uuid + ". " +
-						e.getLocalizedMessage();
-				log.error(msg, e);
-				throw new DlabException(msg, e);
-			}
-		} else {
-			final String scriptName = StringUtils.substringBefore(Paths.get(parser.getCommand()).getFileName()
-					.toString(), ".");
-			String templateFileName = "mock_response/" + cloudProvider.getName() + '/' + scriptName + JSON_FILE_ENDING;
-			responseFileName = getAbsolutePath(parser.getResponsePath(), scriptName + user + "_" +
-					parser.getRequestId() + JSON_FILE_ENDING);
-			setResponse(templateFileName, responseFileName);
-		}
-
-	}
-
-	private void sleep(int ms) {
-		try {
-			Thread.sleep(ms);
-		} catch (InterruptedException e) {
-			log.error("InterruptedException occurred: {}", e.getMessage());
-			Thread.currentThread().interrupt();
-		}
-	}
-
-	private static void copyFile(String sourceFilePath, String destinationFileName, String destinationFolder) throws
-			IOException {
-		File to = new File(getAbsolutePath(destinationFolder, destinationFileName));
-
-		try (InputStream inputStream =
-					 CommandExecutorMockAsync.class.getClassLoader().getResourceAsStream(sourceFilePath);
-			 OutputStream outputStream = new FileOutputStream(to)) {
-			ByteStreams.copy(inputStream, outputStream);
-		}
-
-		log.debug("File {} copied to {}", sourceFilePath, to);
-	}
-
-	/**
-	 * Return absolute path to the file or folder.
-	 *
-	 * @param first part of path.
-	 * @param more  next path components.
-	 */
-	private static String getAbsolutePath(String first, String... more) {
-		return Paths.get(first, more).toAbsolutePath().toString();
-	}
-
-	/**
-	 * Tests the directory exists.
-	 *
-	 * @param dir the name of directory.
-	 * @return <b>true</b> if the directory exists otherwise return <b>false</b>.
-	 */
-	private boolean dirExists(String dir) {
-		File file = new File(dir);
-		return (file.exists() && file.isDirectory());
-	}
-
-	/**
-	 * Find and return the directory "infrastructure-provisioning/src".
-	 *
-	 * @throws FileNotFoundException may be thrown
-	 */
-	private String findTemplatesDir() throws FileNotFoundException {
-		String dir = System.getProperty("docker.dir");
-
-		if (dir != null) {
-			dir = getAbsolutePath(dir);
-			if (dirExists(dir)) {
-				return dir;
-			}
-			throw new FileNotFoundException("Directory \"" + dir + "\" not found. " +
-					"Please set JVM argument -Ddocker.dir to the " +
-					"\".../infrastructure-provisioning/src/general/files/" + cloudProvider.getName() + "\" directory");
-		}
-		dir = getAbsolutePath(
-				".",
-				"../../infrastructure-provisioning/src/general/files/" + cloudProvider.getName());
-		if (dirExists(dir)) {
-			return dir;
-		}
-		dir = getAbsolutePath(
-				ServiceUtils.getUserDir(),
-				"../../infrastructure-provisioning/src/general/files/" + cloudProvider.getName());
-		if (dirExists(dir)) {
-			return dir;
-		}
-		throw new FileNotFoundException("Directory \"" + dir + "\" not found. " +
-				"Please set the value docker.dir property to the " +
-				"\".../infrastructure-provisioning/src/general/files/" + cloudProvider.getName() + "\" directory");
-	}
-
-	/**
-	 * Describe action.
-	 */
-	private void describe() {
-		String templateFileName;
-		try {
-			templateFileName = getAbsolutePath(findTemplatesDir(), parser.getImageType() + "_description.json");
-		} catch (FileNotFoundException e) {
-			throw new DlabException("Cannot describe image " + parser.getImageType() + ". " + e.getLocalizedMessage(),
-					e);
-		}
-		responseFileName = getAbsolutePath(parser.getResponsePath(), parser.getRequestId() + JSON_FILE_ENDING);
-
-		log.debug("Create response file from {} to {}", templateFileName, responseFileName);
-		File fileResponse = new File(responseFileName);
-		File fileTemplate = new File(templateFileName);
-		try {
-			if (!fileTemplate.exists()) {
-				throw new FileNotFoundException("File \"" + fileTemplate + "\" not found.");
-			}
-			if (!fileTemplate.canRead()) {
-				throw new IOException("Cannot read file \"" + fileTemplate + "\".");
-			}
-			Files.createParentDirs(fileResponse);
-			Files.copy(fileTemplate, fileResponse);
-		} catch (IOException e) {
-			throw new DlabException("Can't create response file " + responseFileName + ": " + e.getLocalizedMessage(),
-					e);
-		}
-	}
-
-	/**
-	 * Perform docker action.
-	 *
-	 * @param user   the name of user.
-	 * @param action docker action.
-	 */
-	private void action(String user, DockerAction action) {
-		String resourceType = parser.getResourceType();
-
-		String prefixFileName = (Lists.newArrayList("project", "edge", "dataengine", "dataengine-service")
-				.contains(resourceType) ? resourceType : "notebook") + "_";
-		String templateFileName = "mock_response/" + cloudProvider.getName() + '/' + prefixFileName +
-				action.toString() + JSON_FILE_ENDING;
-		responseFileName = getAbsolutePath(parser.getResponsePath(), prefixFileName + user + "_" +
-				parser.getRequestId() + JSON_FILE_ENDING);
-		setResponse(templateFileName, responseFileName);
-	}
-
-	/**
-	 * Return the section of resource statuses for docker action status.
-	 */
-	private String getResponseStatus(boolean noUpdate) {
-		if (noUpdate) {
-			return "{}";
-		}
-		EnvResourceList resourceList;
-		try {
-			JsonNode json = MAPPER.readTree(parser.getJson());
-			json = json.get("edge_list_resources");
-			resourceList = MAPPER.readValue(json.toString(), EnvResourceList.class);
-		} catch (IOException e) {
-			throw new DlabException("Can't parse json content: " + e.getLocalizedMessage(), e);
-		}
-
-		if (resourceList.getHostList() != null) {
-			for (EnvResource host : resourceList.getHostList()) {
-				host.setStatus(UserInstanceStatus.RUNNING.toString());
-			}
-		}
-		if (resourceList.getClusterList() != null) {
-			for (EnvResource host : resourceList.getClusterList()) {
-				host.setStatus(UserInstanceStatus.RUNNING.toString());
-			}
-		}
-
-		try {
-			return MAPPER.writeValueAsString(resourceList);
-		} catch (JsonProcessingException e) {
-			throw new DlabException("Can't generate json content: " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Return the section of resource statuses for docker action status.
-	 */
-	private String getResponseLibInstall(boolean isSuccess) {
-		List<LibInstallDTO> list;
-		try {
-			JsonNode json = MAPPER.readTree(parser.getJson());
-			json = json.get("libs");
-			list = MAPPER.readValue(json.toString(), new TypeReference<List<LibInstallDTO>>() {
-			});
-		} catch (IOException e) {
-			throw new DlabException("Can't parse json content: " + e.getLocalizedMessage(), e);
-		}
-
-		for (LibInstallDTO lib : list) {
-			if (isSuccess) {
-				lib.setStatus(LibStatus.INSTALLED.toString());
-			} else {
-				lib.setStatus(LibStatus.INSTALLATION_ERROR.toString());
-				lib.setErrorMessage("Mock error message");
-			}
-		}
-
-		try {
-			return MAPPER.writeValueAsString(list);
-		} catch (JsonProcessingException e) {
-			throw new DlabException("Can't generate json content: " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Write response file.
-	 *
-	 * @param sourceFileName template file name.
-	 * @param targetFileName response file name.
-	 */
-	private void setResponse(String sourceFileName, String targetFileName) {
-		String content;
-		URL url = Resources.getResource(sourceFileName);
-		try {
-			content = Resources.toString(url, Charsets.UTF_8);
-		} catch (IOException e) {
-			throw new DlabException("Can't read resource " + sourceFileName + ": " + e.getLocalizedMessage(), e);
-		}
-
-		for (String key : parser.getVariables().keySet()) {
-			String value = parser.getVariables().get(key);
-			content = content.replace("${" + key.toUpperCase() + "}", value);
-		}
-
-		File fileResponse = new File(responseFileName);
-		try (BufferedWriter out = new BufferedWriter(new FileWriter(fileResponse))) {
-			Files.createParentDirs(fileResponse);
-			out.write(content);
-		} catch (IOException e) {
-			throw new DlabException("Can't write response file " + targetFileName + ": " + e.getLocalizedMessage(), e);
-		}
-		log.debug("Create response file from {} to {}", sourceFileName, targetFileName);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandParserMock.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandParserMock.java
deleted file mode 100644
index fe20912..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandParserMock.java
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * 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.core.commands;
-
-import com.epam.dlab.exceptions.DlabException;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.base.MoreObjects;
-import org.apache.commons.lang3.tuple.ImmutablePair;
-import org.apache.commons.lang3.tuple.Pair;
-
-import java.io.IOException;
-import java.util.*;
-
-/**
- * Parse command for emulate commands of Docker.
- */
-public class CommandParserMock {
-    private ObjectMapper MAPPER = new ObjectMapper()
-            .configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true)
-            .setSerializationInclusion(JsonInclude.Include.NON_NULL);
-
-    private String command;
-    private String action;
-    private String resourceType;
-    private String imageType;
-    private String requestId;
-    private String responsePath;
-    private String name;
-    private String json;
-    private Map<String, String> envMap = new HashMap<>();
-    private Map<String, String> varMap = new HashMap<>();
-    private List<String> otherArgs = new ArrayList<>();
-    private Map<String, String> variables = new HashMap<>();
-    private boolean dockerCommand;
-
-    public CommandParserMock() {
-    }
-
-    public CommandParserMock(String command, String uuid) {
-        parse(command, uuid);
-    }
-
-
-    /**
-     * Return the name of docker command.
-     */
-    public String getCommand() {
-        return command;
-    }
-
-    /**
-     * Return the name of docker action.
-     */
-    public String getAction() {
-        return action;
-    }
-
-    /**
-     * Return the type of resource.
-     */
-    public String getResourceType() {
-        return resourceType;
-    }
-
-    /**
-     * Return the image type.
-     */
-    public String getImageType() {
-        return imageType;
-    }
-
-    /**
-     * Return the request id.
-     */
-    public String getRequestId() {
-        return requestId;
-    }
-
-    /**
-     * Return the path for response files.
-     */
-    public String getResponsePath() {
-        return responsePath;
-    }
-
-    /**
-     * Return name of docker container.
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Return content of Json if present otherwise <b>null</b>.
-     */
-    public String getJson() {
-        return json;
-    }
-
-    /**
-     * Return map of environment variables.
-     */
-    public Map<String, String> getVariables() {
-        return variables;
-    }
-
-    /**
-     * Add argument to list.
-     *
-     * @param args list of arguments.
-     * @param arg  argument.
-     */
-    private void addArgToList(List<String> args, String arg) {
-        if (arg == null) {
-            return;
-        }
-        if (arg.length() > 1) {
-            if (arg.startsWith("'") && arg.endsWith("'")) {
-                arg = arg.substring(1, arg.length() - 1);
-            }
-            if (arg.startsWith("\"") && arg.endsWith("\"")) {
-                arg = arg.substring(1, arg.length() - 1);
-            }
-        }
-        arg = arg.trim();
-        if (arg.isEmpty()) {
-            return;
-        }
-
-        args.add(arg);
-    }
-
-    /**
-     * Extract arguments from command line.
-     *
-     * @param cmd command line.
-     * @return List of arguments.
-     */
-    private List<String> extractArgs(String cmd) {
-        boolean isQuote = false;
-        boolean isDoubleQuote = false;
-        List<String> args = new ArrayList<>();
-        int pos = 0;
-
-        for (int i = 0; i < cmd.length(); i++) {
-            final char c = cmd.charAt(i);
-            if (c == '\'') {
-                isQuote = !isQuote;
-                continue;
-            }
-            if (c == '"') {
-                isDoubleQuote = !isDoubleQuote;
-                continue;
-            }
-
-            if (!isQuote && !isDoubleQuote && c == ' ') {
-                addArgToList(args, cmd.substring(pos, i));
-                pos = i + 1;
-            }
-        }
-        if (!isQuote && !isDoubleQuote) {
-            addArgToList(args, cmd.substring(pos));
-        }
-
-        return args;
-    }
-
-    /**
-     * Return the value of argument.
-     *
-     * @param args    list of arguments.
-     * @param index   index of named arguments
-     * @param argName name of argument.
-     */
-    private String getArgValue(List<String> args, int index, String argName) {
-        if (!args.get(index).equals(argName)) {
-            return null;
-        }
-        args.remove(index);
-        if (index < args.size()) {
-            String value = args.get(index);
-            args.remove(index);
-            return value;
-        }
-        throw new DlabException("Argument \"" + argName + "\" detected but not have value");
-    }
-
-    /**
-     * Return pair name/value separated.
-     *
-     * @param argName   name of argument.
-     * @param value     value.
-     * @param separator separator.
-     */
-    private Pair<String, String> getPair(String argName, String value, String separator) {
-        String[] array = value.split(separator);
-        if (array.length != 2) {
-            throw new DlabException("Invalid value for \"" + argName + "\": " + value);
-        }
-        return new ImmutablePair<>(array[0], array[1]);
-    }
-
-    /**
-     * Return name of docker image.
-     *
-     * @param args list of arguments.
-     * @throws if image name not found.
-     */
-    public static String getImageName(List<String> args) {
-        for (String s : args) {
-            if (s.startsWith("docker.dlab-")) {
-                return s;
-            }
-        }
-        throw new DlabException("Name of docker image not found");
-    }
-
-    /**
-     * Extract Json properties from Json content.
-     *
-     * @param jsonContent Json content.
-     * @return
-     */
-    private Map<String, String> getJsonVariables(String jsonContent) {
-        Map<String, String> vars = new HashMap<>();
-        if (jsonContent == null) {
-            return vars;
-        }
-
-        JsonNode json;
-        try {
-            json = MAPPER.readTree(jsonContent);
-        } catch (IOException e) {
-            throw new DlabException("Can't parse json content: " + e.getLocalizedMessage(), e);
-        }
-
-        Iterator<String> keys = json.fieldNames();
-        while (keys.hasNext()) {
-            String key = keys.next();
-            String value = getTextValue(json.get(key));
-            if (value != null) {
-                vars.put(key, value);
-            }
-        }
-        return vars;
-    }
-
-    /**
-     * Return the value of json property or <b>null</b>.
-     *
-     * @param jsonNode - Json node.
-     */
-    private String getTextValue(JsonNode jsonNode) {
-        return jsonNode != null ? jsonNode.textValue() : null;
-    }
-
-    /**
-     * Parse command line.
-     *
-     * @param cmd command line.
-     */
-    public void parse(String cmd, String uuid) {
-        command = null;
-        action = null;
-        resourceType = null;
-        imageType = null;
-        requestId = uuid;
-        responsePath = null;
-        name = null;
-        json = null;
-
-        envMap.clear();
-        varMap.clear();
-        otherArgs.clear();
-        variables.clear();
-
-        List<String> args = extractArgs(cmd);
-        dockerCommand = args.contains("docker");
-        int i = 0;
-        String s;
-        Pair<String, String> p;
-
-        while (i < args.size()) {
-            if ((s = getArgValue(args, i, "-v")) != null) {
-                p = getPair("-v", s, ":");
-                varMap.put(p.getValue(), p.getKey());
-            } else if ((s = getArgValue(args, i, "-e")) != null) {
-                p = getPair("-e", s, "=");
-                envMap.put(p.getKey(), p.getValue());
-            } else if ((s = getArgValue(args, i, "docker")) != null || (s = getArgValue(args, i, "python")) != null) {
-                command = s;
-            } else if ((s = getArgValue(args, i, "--action")) != null) {
-                action = s;
-            } else if ((s = getArgValue(args, i, "--name")) != null) {
-                name = s;
-            } else if ((s = getArgValue(args, i, "echo")) != null) {
-                if (s.equals("-e")) {
-                    if (i >= args.size()) {
-                        throw new DlabException("Argument \"echo -e\" detected but not have value");
-                    }
-                    s = args.get(i);
-                    args.remove(i);
-                }
-                json = s;
-            } else if ((s = getArgValue(args, i, "--result_path")) != null) {
-                responsePath = s;
-                varMap.put("/response", responsePath);
-                args.remove(i);
-            } else {
-                i++;
-            }
-        }
-
-        if (args.size() > 0) {
-            otherArgs.addAll(args);
-        }
-
-        resourceType = envMap.get("conf_resource");
-        if (isDockerCommand()) {
-            imageType = getImageName(args);
-            imageType = imageType.replace("docker.dlab-", "").replace(":latest", "");
-        }
-        responsePath = varMap.get("/response");
-
-        variables.putAll(envMap);
-        variables.putAll(getJsonVariables(json));
-        variables.put("request_id", requestId);
-        variables.put("instance_id", "i-" + requestId.replace("-", "").substring(0, 17));
-        variables.put("cluster_id", "j-" + requestId.replace("-", "").substring(0, 13).toUpperCase());
-        variables.put("notebook_id", requestId.replace("-", "").substring(17, 22));
-    }
-
-    public boolean isDockerCommand() {
-        return dockerCommand;
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(this)
-                .add("command", command)
-                .add("action", action)
-                .add("resourceType", resourceType)
-                .add("imageType", imageType)
-                .add("requestId", requestId)
-                .add("responsePath", responsePath)
-                .add("name", name)
-                .add("environment", envMap)
-                .add("variable", varMap)
-                .add("others", otherArgs)
-                .add("json", json)
-                .toString();
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/DockerAction.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/DockerAction.java
deleted file mode 100644
index dea80e9..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/DockerAction.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.core.commands;
-
-public enum DockerAction {
-    DESCRIBE,
-    CREATE,
-    START,
-    CONFIGURE,
-    RUN,
-    STOP,
-    TERMINATE,
-    LIB_LIST,
-    LIB_INSTALL,
-    GIT_CREDS,
-    CREATE_IMAGE,
-    STATUS,
-	REUPLOAD_KEY,
-    RECONFIGURE_SPARK,
-	CHECK_INACTIVITY;
-
-    public static DockerAction of(String action) {
-        if (action != null) {
-            for (DockerAction uis : DockerAction.values()) {
-                if (action.equalsIgnoreCase(uis.toString())) {
-                    return uis;
-                }
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public String toString() {
-        return super.toString().toLowerCase();
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/DockerCommands.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/DockerCommands.java
deleted file mode 100644
index 6a5f267..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/DockerCommands.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.core.commands;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import java.util.UUID;
-
-@FunctionalInterface
-public interface DockerCommands {
-	String GET_IMAGES = new ImagesDockerCommand()
-			.pipe(UnixCommand.awk("{print $1\":\"$2}"))
-			.pipe(UnixCommand.sort())
-			.pipe(UnixCommand.uniq())
-			.pipe(UnixCommand.grep("dlab"))
-			.pipe(UnixCommand.grep("none", "-v"))
-			.pipe(UnixCommand.grep("base", "-v"))
-			.pipe(UnixCommand.grep("ssn", "-v"))
-			.pipe(UnixCommand.grep("edge", "-v"))
-			.pipe(UnixCommand.grep("project", "-v"))
-			.toCMD();
-
-	String GET_RUNNING_CONTAINERS_FOR_USER = "docker ps --format \"{{.Names}}\" -f name=%s";
-
-	ObjectMapper MAPPER = new ObjectMapper()
-			.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
-
-	static String generateUUID() {
-		return UUID.randomUUID().toString();
-	}
-
-	static String extractUUID(String fileName) {
-		Integer beginIndex = fileName.lastIndexOf('_');
-		Integer endIndex = fileName.lastIndexOf('.');
-		beginIndex = beginIndex < 0 ? 0 : beginIndex + 1;
-		if (endIndex < 0) {
-			endIndex = fileName.length();
-		}
-		if (beginIndex > endIndex) {
-			beginIndex = endIndex;
-		}
-		return fileName.substring(beginIndex, endIndex);
-	}
-
-	default String nameContainer(String... names) {
-		return String.join("_", names) + "_" + System.currentTimeMillis();
-	}
-
-	String getResourceType();
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/ICommandExecutor.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/ICommandExecutor.java
deleted file mode 100644
index 454bc05..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/ICommandExecutor.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.core.commands;
-
-import com.epam.dlab.process.model.ProcessInfo;
-
-public interface ICommandExecutor {
-    ProcessInfo executeSync(String username, String uuid, String command) throws Exception;
-    void executeAsync(String username, String uuid, String command);
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/ImagesDockerCommand.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/ImagesDockerCommand.java
deleted file mode 100644
index ebff5c0..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/ImagesDockerCommand.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.core.commands;
-
-import java.util.LinkedList;
-import java.util.List;
-
-public class ImagesDockerCommand implements CmdCommand {
-    private String command = "docker images";
-
-    private List<UnixCommand> unixCommands;
-
-    public ImagesDockerCommand pipe(UnixCommand unixCommand) {
-        if (unixCommands == null) {
-            unixCommands = new LinkedList<>();
-        }
-        unixCommands.add(unixCommand);
-        return this;
-    }
-
-    @Override
-    public String toCMD() {
-        StringBuilder sb = new StringBuilder(command);
-        if (unixCommands != null) {
-            for (UnixCommand unixCommand : unixCommands) {
-                sb.append(" | ").append(unixCommand.getCommand());
-            }
-        }
-        return sb.toString();
-    }
-
-    @Override
-    public String toString() {
-        return toCMD();
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/PythonBackupCommand.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/PythonBackupCommand.java
deleted file mode 100644
index 20ab144..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/PythonBackupCommand.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.core.commands;
-
-import java.util.List;
-
-public class PythonBackupCommand extends PythonCommand {
-
-	private static final String ARG_DELIMITER = ",";
-	private static final String USER_NAME_SYSTEM_PROPERTY = "user.name";
-
-	public PythonBackupCommand(String fileName) {
-		super(fileName);
-	}
-
-	public PythonBackupCommand withConfig(List<String> configs) {
-		withOption("--config", String.join(ARG_DELIMITER, configs));
-		return this;
-	}
-
-	public PythonBackupCommand withKeys(List<String> keys) {
-		withOption("--keys", String.join(ARG_DELIMITER, keys));
-		return this;
-	}
-
-	public PythonBackupCommand withJars(List<String> jars) {
-		withOption("--jars", String.join(ARG_DELIMITER, jars));
-		return this;
-	}
-
-	public PythonBackupCommand withDBBackup(boolean dbBackup) {
-		if (dbBackup) {
-			withOption("--db");
-		}
-		return this;
-	}
-
-	public PythonBackupCommand withCertificates(List<String> certificates) {
-		withOption("--certs", String.join(ARG_DELIMITER, certificates));
-		return this;
-	}
-
-	public PythonBackupCommand withSystemUser() {
-		withOption("--user", System.getProperty(USER_NAME_SYSTEM_PROPERTY));
-		return this;
-	}
-
-	public PythonBackupCommand withLogsBackup(boolean logsBackup) {
-		if (logsBackup) {
-			withOption("--logs");
-		}
-		return this;
-	}
-
-	public PythonBackupCommand withRequestId(String requestId) {
-		withOption("--request_id", requestId);
-		return this;
-	}
-
-	public PythonBackupCommand withResponsePath(String responsePath) {
-		withOption("--result_path", responsePath);
-		return this;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/PythonCommand.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/PythonCommand.java
deleted file mode 100644
index c3bfe3c..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/PythonCommand.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.core.commands;
-
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class PythonCommand implements CmdCommand {
-	private static final String PYTHON = "python ";
-	private final String fileName;
-	private List<String> options = new ArrayList<>();
-
-	public PythonCommand(String fileName) {
-		this.fileName = fileName;
-	}
-
-	public PythonCommand withOption(String option) {
-		options.add(option);
-		return this;
-	}
-
-	public PythonCommand withOption(String key, String value) {
-		options.add(key + " " + value);
-		return this;
-	}
-
-	@Override
-	public String toCMD() {
-		return PYTHON + fileName + StringUtils.SPACE + String.join(StringUtils.SPACE, options);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/RunDockerCommand.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/RunDockerCommand.java
deleted file mode 100644
index 4c466dc..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/RunDockerCommand.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * 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.core.commands;
-
-import java.nio.file.Paths;
-import java.util.LinkedList;
-import java.util.List;
-
-public class RunDockerCommand implements CmdCommand {
-    public static final String EDGE_USER_NAME_FORMAT = "-e \"edge_user_name=%s\"";
-    private String command = "docker run";
-    private List<String> options = new LinkedList<>();
-    private String image;
-    private DockerAction action;
-
-    private static final String ROOT_KEYS_PATH = "/root/keys";
-    private static final String RESPONSE_PATH = "/response";
-    private static final String LOG_PATH = "/logs";
-    private static final String AZURE_AUTH_FILE = "/root/azure_auth.json";
-
-    public RunDockerCommand withVolume(String hostSrcPath, String bindPath) {
-        options.add(String.format("-v %s:%s", hostSrcPath, bindPath));
-        return this;
-    }
-
-    public RunDockerCommand withVolumeForRootKeys(String hostSrcPath) {
-        return withVolume(hostSrcPath, ROOT_KEYS_PATH);
-    }
-
-    public RunDockerCommand withVolumeForResponse(String hostSrcPath) {
-        return withVolume(hostSrcPath, RESPONSE_PATH);
-    }
-
-    public RunDockerCommand withVolumeFoAzureAuthFile(String hostSrcPath) {
-        return withVolume(hostSrcPath, AZURE_AUTH_FILE);
-    }
-
-    public RunDockerCommand withVolumeForLog(String hostSrcPath, String logDirectory) {
-        return withVolume(Paths.get(hostSrcPath, logDirectory).toString(),
-                Paths.get(LOG_PATH, logDirectory).toString());
-    }
-
-    public RunDockerCommand withName(String name) {
-        options.add(String.format("--name %s", name));
-        return this;
-    }
-
-    public RunDockerCommand withRequestId(String requestId) {
-        options.add(String.format("-e \"request_id=%s\"", requestId));
-        return this;
-    }
-
-    public RunDockerCommand withAtach(String value) {
-        options.add(String.format("-a %s", value));
-        return this;
-    }
-
-    public RunDockerCommand withInteractive() {
-        options.add("-i");
-        return this;
-    }
-
-    public RunDockerCommand withDetached() {
-        options.add("-d");
-        return this;
-    }
-
-    public RunDockerCommand withPseudoTTY() {
-        options.add("-t");
-        return this;
-    }
-
-    public RunDockerCommand withImage(String image) {
-        this.image = image;
-        return this;
-    }
-
-    public RunDockerCommand withAction(DockerAction action) {
-        this.action = action;
-        return this;
-    }
-
-    public RunDockerCommand withActionDescribe(String toDescribe) {
-        this.image = toDescribe;
-        this.action = DockerAction.DESCRIBE;
-        return this;
-    }
-
-    public RunDockerCommand withActionCreate(String toCreate) {
-        this.image = toCreate;
-        this.action = DockerAction.CREATE;
-        return this;
-    }
-
-    public RunDockerCommand withActionConfigure(String toConfigue) {
-        this.image = toConfigue;
-        this.action = DockerAction.CONFIGURE;
-        return this;
-    }
-
-    public RunDockerCommand withActionStatus(String toStatus) {
-        this.image = toStatus;
-        this.action = DockerAction.STATUS;
-        return this;
-    }
-
-    public RunDockerCommand withActionStart(String toStart) {
-        this.image = toStart;
-        this.action = DockerAction.START;
-        return this;
-    }
-
-    public RunDockerCommand withActionRun(String toRun) {
-        this.image = toRun;
-        this.action = DockerAction.RUN;
-        return this;
-    }
-
-    public RunDockerCommand withActionTerminate(String toTerminate) {
-        this.image = toTerminate;
-        this.action = DockerAction.TERMINATE;
-        return this;
-    }
-
-    public RunDockerCommand withActionStop(String toStop) {
-        this.image = toStop;
-        this.action = DockerAction.STOP;
-        return this;
-    }
-
-    public RunDockerCommand withConfKeyName(String confKeyName) {
-        options.add(String.format("-e \"conf_key_name=%s\"", confKeyName));
-        return this;
-    }
-
-    public RunDockerCommand withConfServiceBaseName(String confServiceBaseName) {
-        options.add(String.format("-e \"conf_service_base_name=%s\"", confServiceBaseName));
-        return this;
-    }
-
-    public RunDockerCommand withConfOsFamily(String confOsFamily) {
-        options.add(String.format("-e \"conf_os_family=%s\"", confOsFamily));
-        return this;
-    }
-
-    public RunDockerCommand withEmrInstanceCount(String emrInstanceCount) {
-        options.add(String.format("-e \"emr_instance_count=%s\"", emrInstanceCount));
-        return this;
-    }
-
-    public RunDockerCommand withAwsVpcId(String awsVpcId) {
-        options.add(String.format("-e \"aws_vpc_id=%s\"", awsVpcId));
-        return this;
-    }
-
-    public RunDockerCommand withAwsSubnetId(String awsSubnetId) {
-        options.add(String.format("-e \"aws_subnet_id=%s\"", awsSubnetId));
-        return this;
-    }
-
-    public RunDockerCommand withEmrInstanceType(String emrInstanceType) {
-        options.add(String.format("-e \"emr_instance_type=%s\"", emrInstanceType));
-        return this;
-    }
-
-    public RunDockerCommand withEmrVersion(String emrVersion) {
-        options.add(String.format("-e \"emr_version=%s\"", emrVersion));
-        return this;
-    }
-
-    public RunDockerCommand withEmrTimeout(String emrTimeout) {
-        options.add(String.format("-e \"emr_timeout=%s\"", emrTimeout));
-        return this;
-    }
-
-    public RunDockerCommand withEc2Role(String ec2Role) {
-        options.add(String.format("-e \"ec2_role=%s\"", ec2Role));
-        return this;
-    }
-
-    public RunDockerCommand withServiceRole(String serviceRole) {
-        options.add(String.format("-e \"service_role=%s\"", serviceRole));
-        return this;
-    }
-
-    public RunDockerCommand withNotebookName(String notebookName) {
-        options.add(String.format("-e \"notebook_name=%s\"", notebookName));
-        return this;
-    }
-
-    public RunDockerCommand withEdgeSubnetCidr(String edgeSubnetCidr) {
-        options.add(String.format("-e \"edge_subnet_cidr=%s\"", edgeSubnetCidr));
-        return this;
-    }
-
-    public RunDockerCommand withAwsRegion(String awsRegion) {
-        options.add(String.format("-e \"aws_region=%s\"", awsRegion));
-        return this;
-    }
-
-    public RunDockerCommand withEdgeUserName(String edgeUserName) {
-        options.add(String.format(EDGE_USER_NAME_FORMAT, edgeUserName));
-        return this;
-    }
-
-    public RunDockerCommand withEmrClusterName(String emrClusterName) {
-        options.add(String.format("-e \"emr_cluster_name=%s\"", emrClusterName));
-        return this;
-    }
-
-    public RunDockerCommand withNotebookUserName(String notebookUserName) {
-        options.add(String.format(EDGE_USER_NAME_FORMAT, notebookUserName));
-        return this;
-    }
-
-    public RunDockerCommand withNotebookSubnetCidr(String notebookSubnetCidr) {
-        options.add(String.format("-e \"notebook_subnet_cidr=%s\"", notebookSubnetCidr));
-        return this;
-    }
-
-    public RunDockerCommand withAwsSecurityGroupsIds(String awsSecurityGroupsIds) {
-        options.add(String.format("-e \"aws_security_groups_ids=%s\"", awsSecurityGroupsIds));
-        return this;
-    }
-
-    public RunDockerCommand withNotebookInstanceName(String notebookInstanceName) {
-        options.add(String.format("-e \"notebook_instance_name=%s\"", notebookInstanceName));
-        return this;
-    }
-
-    public RunDockerCommand withUserKeyName(String userKeyName) {
-        options.add(String.format(EDGE_USER_NAME_FORMAT, userKeyName));
-        return this;
-    }
-
-    public RunDockerCommand withDryRun() {
-        options.add("-e \"dry_run=true\"");
-        return this;
-    }
-
-    public RunDockerCommand withResource(String resourceType) {
-        options.add(String.format("-e \"conf_resource=%s\"", resourceType));
-        return this;
-    }
-
-    public RunDockerCommand withRemove(){
-        options.add("--rm");
-        return this;
-    }
-
-    @Override
-    public String toCMD() {
-        StringBuilder sb = new StringBuilder(command);
-        for (String option : options) {
-            sb.append(" ").append(option);
-        }
-        if (image != null && action != null) {
-            sb.append(" ").append(image).append(" --action ").append(action.toString());
-        }
-        return sb.toString();
-    }
-
-    @Override
-    public String toString() {
-        return toCMD();
-    }
-    
-}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/UnixCommand.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/UnixCommand.java
deleted file mode 100644
index 9a9095a..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/UnixCommand.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.core.commands;
-
-public class UnixCommand {
-    private String command;
-
-    public UnixCommand(String command) {
-        this.command = command;
-    }
-
-    public static UnixCommand awk(String txt) {
-        return new UnixCommand("awk '" + txt + "'");
-    }
-
-    public static UnixCommand sort() {
-        return new UnixCommand("sort");
-    }
-
-    public static UnixCommand uniq() {
-        return new UnixCommand("uniq");
-    }
-
-    public static UnixCommand grep(String searchFor, String... options) {
-        StringBuilder sb = new StringBuilder("grep");
-        for (String option : options) {
-            sb.append(' ').append(option);
-        }
-        sb.append(" \"" + searchFor + "\"");
-        return new UnixCommand(sb.toString());
-    }
-
-    public String getCommand() {
-        return command;
-    }
-}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/AsyncFileHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/AsyncFileHandler.java
deleted file mode 100644
index 52a2066..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/AsyncFileHandler.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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.core.response.folderlistener;
-
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import io.dropwizard.util.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.function.Supplier;
-
-import static com.epam.dlab.backendapi.core.Constants.JSON_EXTENSION;
-import static com.epam.dlab.backendapi.core.Constants.LOG_EXTENSION;
-
-/* Handler for the file processing.
- */
-public final class AsyncFileHandler implements Supplier<Boolean> {
-
-	private static final Logger LOGGER = LoggerFactory.getLogger(AsyncFileHandler.class);
-
-	/**
-	 * File name.
-	 */
-	private final String fileName;
-	/**
-	 * Directory name.
-	 */
-	private final String directory;
-	/**
-	 * Implement of the file handler.
-	 */
-	private final FileHandlerCallback fileHandlerCallback;
-	/**
-	 * Timeout waiting for the file writing.
-	 */
-	private final Duration fileLengthCheckDelay;
-
-	/**
-	 * Create instance of the file handler.
-	 *
-	 * @param fileName             file name.
-	 * @param directory            directory name.
-	 * @param fileHandlerCallback  file handler for processing
-	 * @param fileLengthCheckDelay timeout waiting for the file writing.
-	 */
-	public AsyncFileHandler(String fileName, String directory, FileHandlerCallback fileHandlerCallback,
-							Duration fileLengthCheckDelay) {
-		this.fileName = fileName;
-		this.directory = directory;
-		this.fileHandlerCallback = fileHandlerCallback;
-		this.fileLengthCheckDelay = fileLengthCheckDelay;
-	}
-
-	@Override
-	public Boolean get() {
-		Path path = Paths.get(directory, fileName);
-		try {
-			boolean result = fileHandlerCallback.handle(fileName, readBytes(path));
-			if (result) {
-				try {
-					Files.deleteIfExists(path);
-					Files.deleteIfExists(getLogFile());
-					LOGGER.trace("Response {} and log files has been deleted", path.toAbsolutePath());
-				} catch (IOException e) {
-					LOGGER.warn("Can't delete file {}", path.toAbsolutePath(), e);
-				}
-			}
-			return result;
-		} catch (Exception e) {
-			LOGGER.error("Could not handle file {} async", path.toAbsolutePath(), e);
-			fileHandlerCallback.handleError(e.getLocalizedMessage());
-		}
-		return false;
-	}
-
-	/**
-	 * Returns the name of log file.
-	 */
-	private Path getLogFile() {
-		return Paths.get(directory, fileName.replaceAll(JSON_EXTENSION, LOG_EXTENSION));
-	}
-
-	/**
-	 * Returns the content of file.
-	 *
-	 * @param path source file.
-	 * @return File content.
-	 * @throws IOException
-	 * @throws InterruptedException
-	 */
-	private byte[] readBytes(Path path) throws IOException, InterruptedException {
-		File file = path.toFile();
-		waitFileCompletelyWritten(file);
-		return Files.readAllBytes(path);
-	}
-
-	/**
-	 * Waiting for the file writing. This method is blocking and return control when
-	 * the file will no longer resize.
-	 *
-	 * @param file source file.
-	 */
-	private void waitFileCompletelyWritten(File file) throws InterruptedException {
-		long before;
-		long after = file.length();
-		do {
-			before = after;
-			Thread.sleep(fileLengthCheckDelay.toMilliseconds());
-			after = file.length();
-		} while (before != after);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/FolderListener.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/FolderListener.java
deleted file mode 100644
index c137e76..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/FolderListener.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * 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.core.response.folderlistener;
-
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.response.folderlistener.WatchItem.ItemStatus;
-import com.epam.dlab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
-import com.epam.dlab.exceptions.DlabException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.epam.dlab.backendapi.core.Constants.JSON_EXTENSION;
-
-/**
- * Listen the directories for the files creation and runs the file processing by {@link AsyncFileHandler}.
- */
-public class FolderListener implements Runnable {
-	private static final Logger LOGGER = LoggerFactory.getLogger(FolderListener.class);
-	/**
-	 * Timeout of the check the file creation in milliseconds.
-	 */
-	public static final long LISTENER_TIMEOUT_MILLLIS = 1000;
-	/**
-	 * Timeout of the idle for the folder listener in milliseconds.
-	 */
-	public static final long LISTENER_IDLE_TIMEOUT_MILLLIS = 600L * 1000L;
-	/**
-	 * Timeout of waiting for the directory creation in milliseconds.
-	 */
-	private static final long WAIT_DIR_TIMEOUT_MILLIS = 500;
-
-	/**
-	 * List of the folder listeners.
-	 */
-	private static final List<FolderListener> listeners = new ArrayList<>();
-	/**
-	 * Thread of the folder listener.
-	 */
-	private Thread thread;
-	/**
-	 * List of the file handles.
-	 */
-	private WatchItemList itemList;
-	/**
-	 * Flag of listening status.
-	 */
-	private boolean isListen = false;
-	/**
-	 * Time when expired of idle for folder listener in milliseconds.
-	 */
-	private long expiredIdleMillis = 0;
-
-
-	private FolderListener() {
-	}
-
-	/**
-	 * Creates thread of the folder listener
-	 *
-	 * @param directoryName Name of directory.
-	 * @param dao
-	 */
-	private FolderListener(String directoryName, CallbackHandlerDao dao) {
-		itemList = new WatchItemList(directoryName, dao);
-	}
-
-	/**
-	 * Appends the file handler for processing to the folder listener and returns instance of the file handler.
-	 *
-	 * @param directoryName        Name of directory for listen.
-	 * @param fileHandlerCallback  File handler for processing.
-	 * @param timeoutMillis        Timeout waiting for the file creation in milliseconds.
-	 * @param fileLengthCheckDelay Timeout waiting for the file writing in milliseconds.
-	 * @param callbackHandlerDao   callbackHandlerDao for handlers
-	 * @return Instance of the file handler.
-	 */
-	public static WatchItem listen(String directoryName, FileHandlerCallback fileHandlerCallback,
-								   long timeoutMillis, long fileLengthCheckDelay,
-								   CallbackHandlerDao callbackHandlerDao) {
-		return listen(directoryName, fileHandlerCallback, timeoutMillis, fileLengthCheckDelay, null,
-				callbackHandlerDao);
-	}
-
-	/**
-	 * Appends the file handler for processing to the folder listener for the existing file and returns
-	 * instance of the file handler. If the file name is <b>null</b> this means that file does not exist
-	 * and equal to call method
-	 * {@link FolderListener#listen(String, FileHandlerCallback, long, long, CallbackHandlerDao)}.
-	 *
-	 * @param directoryName        Name of directory for listen.
-	 * @param fileHandlerCallback  File handler for processing.
-	 * @param timeoutMillis        Timeout waiting for the file creation in milliseconds.
-	 * @param fileLengthCheckDelay Timeout waiting for the file writing in milliseconds.
-	 * @param fileName             file name.
-	 * @param callbackHandlerDao   callbackHandlerDao for handlers
-	 * @return Instance of the file handler.
-	 */
-	public static WatchItem listen(String directoryName, FileHandlerCallback fileHandlerCallback, long timeoutMillis,
-								   long fileLengthCheckDelay, String fileName, CallbackHandlerDao callbackHandlerDao) {
-		FolderListener listener;
-		WatchItem item;
-
-		LOGGER.trace("Looking for folder listener to folder \"{}\" ...", directoryName);
-		synchronized (listeners) {
-			for (int i = 0; i < listeners.size(); i++) {
-				listener = listeners.get(i);
-				if (listener.itemList.getDirectoryName().equals(directoryName)) {
-					if (listener.isAlive()) {
-						LOGGER.debug("Folder listener \"{}\" found. Append file handler for UUID {}",
-								directoryName, fileHandlerCallback.getUUID());
-						item = listener.itemList.append(fileHandlerCallback, timeoutMillis, fileLengthCheckDelay,
-								fileName);
-						return item;
-					} else {
-						LOGGER.warn("Folder listener \"{}\" is dead and will be removed", directoryName);
-						listeners.remove(i);
-						break;
-					}
-				}
-			}
-			LOGGER.debug("Folder listener \"{}\" not found. Create new listener and append file handler for UUID {}",
-					directoryName, fileHandlerCallback.getUUID());
-			listener = new FolderListener(directoryName, callbackHandlerDao);
-			item = listener.itemList.append(fileHandlerCallback, timeoutMillis, fileLengthCheckDelay, fileName);
-			listeners.add(listener);
-			listener.start();
-		}
-		return item;
-	}
-
-	/**
-	 * Terminates all the folder listeners.
-	 */
-	public static void terminateAll() {
-		FolderListener[] array;
-		synchronized (listeners) {
-			array = listeners.toArray(new FolderListener[listeners.size()]);
-		}
-		for (int i = 0; i < array.length; i++) {
-			array[i].terminate();
-		}
-	}
-
-	/**
-	 * Returns the list of folder listeners.
-	 */
-	public static List<FolderListener> getListeners() {
-		return listeners;
-	}
-
-	/**
-	 * Starts the thread of the folder listener.
-	 */
-	protected void start() {
-		thread = new Thread(this, getClass().getSimpleName() + "-" + listeners.size());
-		thread.start();
-	}
-
-	/**
-	 * Terminates the thread of the folder listener.
-	 */
-	protected void terminate() {
-		if (thread != null) {
-			LOGGER.debug("Folder listener \"{}\" will be terminate", getDirectoryName());
-			thread.interrupt();
-		}
-	}
-
-	/**
-	 * Returns <b>true</b> if the folder listener thread is running and is alive, otherwise <b>false</b>.
-	 */
-	public boolean isAlive() {
-		return (thread != null && thread.isAlive());
-	}
-
-	/**
-	 * Returns <b>true</b> if the folder listener is listening the folder.
-	 */
-	public boolean isListen() {
-		return isListen;
-	}
-
-
-	/**
-	 * Returns the list of the file handlers.
-	 */
-	public WatchItemList getItemList() {
-		return itemList;
-	}
-
-	/**
-	 * Returns the full name of directory.
-	 */
-	public String getDirectoryName() {
-		return itemList.getDirectoryFullName();
-	}
-
-	/**
-	 * Waiting for the directory creation and returns <b>true</b> if it exists or created.
-	 * If timeout has expired and directory was not created returns <b>false</b>
-	 */
-	private boolean waitForDirectory() throws InterruptedException {
-		File file = new File(getDirectoryName());
-		if (file.exists()) {
-			return true;
-		} else {
-			LOGGER.trace("Folder listener \"{}\" waiting for the directory creation", getDirectoryName());
-		}
-
-		long expiredTimeMillis = itemList.get(0).getExpiredTimeMillis();
-		while (expiredTimeMillis >= System.currentTimeMillis()) {
-			Thread.sleep(WAIT_DIR_TIMEOUT_MILLIS);
-			if (file.exists()) {
-				return true;
-			}
-		}
-		LOGGER.error("Folder listener \"{}\" error. Timeout has expired and directory does not exist",
-				getDirectoryName());
-		return false;
-	}
-
-	/**
-	 * Initializes the thread of the folder listener. Returns <b>true</b> if the initialization
-	 * completed successfully. Returns <b>false</b> if all the file handlers has been processed
-	 * or initialization fails.
-	 */
-	private boolean init() {
-		LOGGER.trace("Folder listener initializing for \"{}\" ...", getDirectoryName());
-
-		try {
-			if (!waitForDirectory()) {
-				return false;
-			}
-		} catch (InterruptedException e) {
-			LOGGER.debug("Folder listener \"{}\" has been interrupted", getDirectoryName());
-			Thread.currentThread().interrupt();
-			return false;
-		}
-
-		processStatusItems();
-		if (itemList.size() == 0) {
-			LOGGER.debug("Folder listener \"{}\" have no files and will be finished", getDirectoryName());
-			return false;
-		}
-
-		LOGGER.trace("Folder listener has been initialized for \"{}\" ...", getDirectoryName());
-		return true;
-	}
-
-	/**
-	 * Process all the file handlers if need and removes all expired, processed or interrupted
-	 * the file handlers from the list of the file handlers.
-	 */
-	private void processStatusItems() {
-		int i = 0;
-
-		if (itemList.size() > 0) {
-			expiredIdleMillis = 0;
-		}
-		itemList.processItemAll();
-
-		synchronized (itemList) {
-			while (i < itemList.size()) {
-				final WatchItem item = itemList.get(i);
-				final ItemStatus status = item.getStatus();
-				final String uuid = item.getFileHandlerCallback().getUUID();
-
-				switch (status) {
-					case WAIT_FOR_FILE:
-					case FILE_CAPTURED:
-					case INPROGRESS:
-						// Skip
-						i++;
-						continue;
-					case TIMEOUT_EXPIRED:
-						LOGGER.warn("Folder listener \"{}\" remove expired file handler for UUID {}", getDirectoryName
-								(), uuid);
-						try {
-							item.getFileHandlerCallback().handleError("Request timeout expired");
-						} catch (Exception e) {
-							LOGGER.error("Folder listener \"{}\" caused exception for UUID {}", getDirectoryName(),
-									uuid, e);
-						}
-						break;
-					case IS_DONE:
-						if (item.getFutureResult()) {
-							LOGGER.trace("Folder listener \"{}\" remove processed file handler for UUID {}, handler " +
-									"result is {}", getDirectoryName(), uuid, item.getFutureResult());
-						} else {
-							LOGGER.warn("Folder listener \"{}\" remove processed file handler for UUID {}, handler " +
-									"result is {}", getDirectoryName(), uuid, item.getFutureResult());
-						}
-						break;
-					case IS_CANCELED:
-						LOGGER.debug("Folder listener \"{}\" remove canceled file handler for UUID {}",
-								getDirectoryName(), uuid);
-						break;
-					case IS_FAILED:
-						LOGGER.warn("Folder listener \"{}\" remove failed file handler for UUID {}", getDirectoryName
-								(), uuid);
-						break;
-					case IS_INTERRUPTED:
-						LOGGER.debug("Folder listener \"{}\" remove iterrupted file handler for UUID {}",
-								getDirectoryName(), uuid);
-						break;
-					default:
-						continue;
-				}
-				itemList.remove(i);
-			}
-		}
-
-		if (expiredIdleMillis == 0 && itemList.size() == 0) {
-			expiredIdleMillis = System.currentTimeMillis() + LISTENER_IDLE_TIMEOUT_MILLLIS;
-		}
-	}
-
-	/**
-	 * Removes the listener from the list of folder listeners if the the file handler list is empty
-	 * and idle time has expired or if <b>force</b> flag has been set to <b>true</b>.
-	 *
-	 * @param force the flag of remove the folder listener immediately.
-	 * @return <b>true</b> if the folder listener has been removed otherwise <b>false</>.
-	 */
-	private boolean removeListener(boolean force) {
-		synchronized (listeners) {
-			if (force || (expiredIdleMillis != 0 && expiredIdleMillis < System.currentTimeMillis())) {
-				for (int i = 0; i < listeners.size(); i++) {
-					if (listeners.get(i) == this) {
-						isListen = false;
-						listeners.remove(i);
-						LOGGER.debug("Folder listener \"{}\" has been removed from pool", getDirectoryName());
-						return true;
-					}
-				}
-			}
-		}
-		return false;
-	}
-
-	/**
-	 * Find and return the list of files to process.
-	 */
-	private String[] getNewFiles() {
-		File dir = new File(getDirectoryName());
-		return dir.list((File dir1, String name) -> {
-			if (name.toLowerCase().endsWith(JSON_EXTENSION)) {
-				WatchItem item = itemList.getItem(name);
-				return (item != null && item.getStatus() == ItemStatus.WAIT_FOR_FILE);
-			}
-			return false;
-		});
-	}
-
-	/**
-	 * Waiting for files and process it.
-	 */
-	private void pollFile() {
-		try {
-			isListen = true;
-			while (true) {
-				String[] fileList = getNewFiles();
-				if (fileList != null) {
-					for (String fileName : fileList) {
-						LOGGER.trace("Folder listener \"{}\" handes the file {}", getDirectoryName(), fileName);
-						processItem(fileName);
-					}
-				}
-
-				processStatusItems();
-				if (removeListener(false)) {
-					LOGGER.debug("Folder listener \"{}\" have no files and will be finished", getDirectoryName());
-					break;
-				}
-				Thread.sleep(LISTENER_TIMEOUT_MILLLIS);
-			}
-		} catch (InterruptedException e) {
-			removeListener(true);
-			LOGGER.debug("Folder listener \"{}\" has been interrupted", getDirectoryName());
-			Thread.currentThread().interrupt();
-		} catch (Exception e) {
-			removeListener(true);
-			LOGGER.error("Folder listener for \"{}\" closed with error.", getDirectoryName(), e);
-			throw new DlabException("Folder listener for \"" + getDirectoryName() + "\" closed with error. " + e
-					.getLocalizedMessage(), e);
-		}
-	}
-
-	private void processItem(String fileName) {
-		try {
-			WatchItem item = itemList.getItem(fileName);
-			item.setFileName(fileName);
-			if (itemList.processItem(item)) {
-				LOGGER.debug("Folder listener \"{}\" processes the file {}", getDirectoryName(),
-						fileName);
-			}
-		} catch (Exception e) {
-			LOGGER.warn("Folder listener \"{}\" has got exception for check or process the file {}",
-					getDirectoryName(), fileName, e);
-		}
-	}
-
-	@Override
-	public void run() {
-		if (init()) {
-			pollFile();
-		} else {
-			LOGGER.warn("Folder listener has not been initialized for \"{}\"", getDirectoryName());
-			removeListener(true);
-		}
-	}
-}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/FolderListenerExecutor.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/FolderListenerExecutor.java
deleted file mode 100644
index 30d8157..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/FolderListenerExecutor.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.core.response.folderlistener;
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import io.dropwizard.util.Duration;
-
-import static com.epam.dlab.backendapi.core.response.folderlistener.FolderListener.listen;
-
-/**
- * Starts asynchronously of waiting for file creation and processing this file.
- */
-@Singleton
-public class FolderListenerExecutor {
-	@Inject
-	private ProvisioningServiceApplicationConfiguration configuration;
-	@Inject
-	private CallbackHandlerDao handlerDao;
-
-	/**
-	 * Starts asynchronously of waiting for file creation and processes this file if the timeout
-	 * has not expired. If timeout has been expired then writes warning message to log file and
-	 * finishes waiting. This method is <b>non-blocking</b>.
-	 *
-	 * @param directory           name of directory for waiting for the file creation.
-	 * @param timeout             timeout for waiting.
-	 * @param fileHandlerCallback handler for the file processing.
-	 */
-	public void start(String directory, Duration timeout, FileHandlerCallback fileHandlerCallback) {
-		CallbackHandlerDao dao = configuration.isHandlersPersistenceEnabled() ? handlerDao : null;
-		listen(directory, fileHandlerCallback, timeout.toMilliseconds(),
-				configuration.getFileLengthCheckDelay().toMilliseconds(), dao);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/WatchItem.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/WatchItem.java
deleted file mode 100644
index bb8fc03..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/WatchItem.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * 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.core.response.folderlistener;
-
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.google.common.base.MoreObjects;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-/**
- * Class to store the file handler for processing.
- */
-@Slf4j
-public class WatchItem implements Comparable<WatchItem> {
-
-	/** Status of file processing.
-	 * <pre>
-	 * WAIT_FOR_FILE waiting for the file creation.
-	 * TIMEOUT_EXPIRED the timeout expired for the file creation.
-	 * FILE_CAPTURED the file created and handled.
-	 * INPROGRESS the file processing is running.
-	 * IS_DONE the file processing is done. You can check the result of processing {@link WatchItem#getFutureResult()}
-	 * IS_CANCELED the file processing has been canceled.
-	 * IS_INTERRUPTED the file processing has been interrupted.
-	 * IS_FAILED the file processing is failed.
-	 * </pre>
-	 *  */
-	public enum ItemStatus {
-		WAIT_FOR_FILE,
-		TIMEOUT_EXPIRED,
-		FILE_CAPTURED,
-		INPROGRESS,
-		IS_DONE,
-		IS_CANCELED,
-		IS_INTERRUPTED,
-		IS_FAILED
-	}
-	
-	/** File handler for processing. */
-	private final FileHandlerCallback fileHandlerCallback;
-	/** Timeout waiting for the file creation in milliseconds. */
-    private final long timeoutMillis;
-    /** Timeout waiting for the file writing in milliseconds. */
-    private final long fileLengthCheckDelay;
-
-    /** Time when expired for the file creation in milliseconds. */
-    private long expiredTimeMillis;
-    /** File name. */
-	private String fileName;
-	/** Future for asynchronously the file processing. */
-	private CompletableFuture<Boolean> future;
-	/** Result of the file processing. */
-	private Boolean futureResult = null;
-
-	/** Creates instance of the file handler.
-	 * @param fileHandlerCallback File handler for processing.
-	 * @param timeoutMillis Timeout waiting for the file creation in milliseconds.
-	 * @param fileLengthCheckDelay Timeout waiting for the file writing in milliseconds.
-	 */
-	public WatchItem(FileHandlerCallback fileHandlerCallback, long timeoutMillis, long fileLengthCheckDelay) {
-		this.fileHandlerCallback = fileHandlerCallback;
-		this.timeoutMillis = timeoutMillis;
-		this.fileLengthCheckDelay = fileLengthCheckDelay;
-	    setExpiredTimeMillis(timeoutMillis);
-	}
-
-	@Override
-	public int compareTo(WatchItem o) {
-		if (o == null) {
-			return -1;
-		}
-		return (fileHandlerCallback.checkUUID(o.fileHandlerCallback.getUUID()) ?
-					0 : fileHandlerCallback.getUUID().compareTo(o.fileHandlerCallback.getUUID()));
-	}
-	
-	/** Returns the file handler for processing. */
-	public FileHandlerCallback getFileHandlerCallback() {
-		return fileHandlerCallback;
-	}
-	
-	/** Returns the timeout waiting for the file creation in milliseconds. */
-	public long getTimeoutMillis() {
-		return timeoutMillis;
-	}
-
-	/** Returns the timeout waiting for the file writing in milliseconds. */
-	public long getFileLengthCheckDelay() {
-		return fileLengthCheckDelay;
-	}
-
-
-	/** Returns the time when expired for the file creation in milliseconds. */
-	public long getExpiredTimeMillis() {
-		return expiredTimeMillis;
-	}
-	
-	/** Sets time when expired for file creation in milliseconds.
-	 * @param expiredTimeMillis time expired for file creation in milliseconds. */
-	private void setExpiredTimeMillis(long expiredTimeMillis) {
-		this.expiredTimeMillis = System.currentTimeMillis() + expiredTimeMillis;
-	}
-
-	/** Returns the file name. */
-	public String getFileName() {
-		return fileName;
-	}
-
-	/** Sets the file name.
-	 * @param fileName file name.
-	 */
-	protected void setFileName(String fileName) {
-		this.fileName = fileName;
-	}
-
-	/** Returns the status of the file processing.
-	 *  See {@link ItemStatus} for details. */
-    public ItemStatus getStatus() {
-		if (fileName == null) {
-    		return (expiredTimeMillis < System.currentTimeMillis() ? ItemStatus.TIMEOUT_EXPIRED : ItemStatus.WAIT_FOR_FILE); 
-    	} else if (future == null) {
-    		return ItemStatus.FILE_CAPTURED;
-    	} else if (future.isCancelled()) {
-    		return ItemStatus.IS_CANCELED;
-    	}
-    	
-    	if (future.isDone()) {
-    		try {
-				futureResult = future.get();
-				return ItemStatus.IS_DONE;
-			} catch (InterruptedException e) {
-    			Thread.currentThread().interrupt();
-				return ItemStatus.IS_INTERRUPTED;
-		    } catch (ExecutionException e) {
-			    log.error("Execution exception occurred", e);
-			    return ItemStatus.IS_FAILED;
-		    }
-    	}
-    	
-    	return ItemStatus.INPROGRESS;
-    }
-
-	/** Returns <b>true</> if the time has expired for the file creation. */
-	public boolean isExpired() {
-		return (fileName == null && expiredTimeMillis < System.currentTimeMillis());
-	}
-
-
-	/** Returns the future for asynchronously the file processing. */
-	public CompletableFuture<Boolean> getFuture() {
-		return future;
-	}
-	
-	/** Sets the future for the file processing.
-	 * @param future completable future for file processing. 
-	 */
-	protected void setFuture(CompletableFuture<Boolean> future) {
-		this.future = future;
-	}
-	
-	/** Returns the result of the file processing. This method is non-blocking and returns <b>true</b>
-	 * or <b>false</b> if the file processing has done, otherwise returns <b>null</b>. */
-	public Boolean getFutureResult() {
-		if (futureResult == null && future != null && future.isDone()) {
-			try {
-				futureResult = future.get();
-			} catch (Exception e) {
-				log.error("Exception occurred during getting result: {}", e.getMessage(), e);
-			}
-		}
-		return futureResult; 
-	}
-	
-	/** Returns the result of the file processing. This method is blocking and returns <b>true</b> or
-	 * <b>false</b> when the file processing has done. */
-	public Boolean getFutureResultSync() throws InterruptedException, ExecutionException {
-		if (futureResult == null && future != null) {
-			futureResult = future.get();
-		}
-		return futureResult;
-	}
-	
-	@Override
-	public String toString() {
-		return MoreObjects.toStringHelper(this)
-				.add("fileHandlerCallback", fileHandlerCallback)
-				.add("timeoutMillis", timeoutMillis)
-				.add("fileLengthCheckDelay", fileLengthCheckDelay)
-				.add("expiredTimeMillis", expiredTimeMillis)
-				.add("fileName", fileName)
-				.add("future", future)
-				.add("futureResult", futureResult)
-				.toString();
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/WatchItemList.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/WatchItemList.java
deleted file mode 100644
index 25141d9..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/folderlistener/WatchItemList.java
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * 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.core.response.folderlistener;
-
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.response.folderlistener.WatchItem.ItemStatus;
-import com.epam.dlab.backendapi.core.response.handlers.PersistentFileHandler;
-import com.epam.dlab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
-import io.dropwizard.util.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.nio.file.Paths;
-import java.util.Collections;
-import java.util.Objects;
-import java.util.Vector;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ForkJoinPool;
-
-/**
- * List of the file handlers for processing.
- */
-public class WatchItemList {
-	private static final Logger LOGGER = LoggerFactory.getLogger(WatchItemList.class);
-
-	/**
-	 * Directory name.
-	 */
-	private final String directoryName;
-	/**
-	 * Directory full name.
-	 */
-	private final String directoryFullName;
-	private final CallbackHandlerDao handlerDao;
-
-	/**
-	 * List of the file handlers.
-	 */
-	private final Vector<WatchItem> list = new Vector<>();
-
-	/**
-	 * UUID of the file handler for search.
-	 */
-	private String uuidSearch;
-
-	/**
-	 * File handler for search.
-	 */
-	private final FileHandlerCallback handlerSearch = new FileHandlerCallback() {
-		@Override
-		public String getUUID() {
-			return uuidSearch;
-		}
-
-		@Override
-		public boolean checkUUID(String uuid) {
-			return uuidSearch.equals(uuid);
-		}
-
-		@Override
-		public void handleError(String errorMessage) {
-		}
-
-		@Override
-		public String getUser() {
-			return "DLAB";
-		}
-
-		@Override
-		public boolean handle(String fileName, byte[] content) throws Exception {
-			return false;
-		}
-	};
-
-	/**
-	 * Creates instance of the file handlers for processing.
-	 *
-	 * @param directoryName listener directory name.
-	 * @param handlerDao    data access object for callback handler
-	 */
-	public WatchItemList(String directoryName, CallbackHandlerDao handlerDao) {
-		this.directoryName = directoryName;
-		this.directoryFullName = Paths.get(directoryName).toAbsolutePath().toString();
-		this.handlerDao = handlerDao;
-	}
-
-	/**
-	 * Returns directory name.
-	 */
-	public String getDirectoryName() {
-		return directoryName;
-	}
-
-	/**
-	 * Returns directory full name.
-	 */
-	public String getDirectoryFullName() {
-		return directoryFullName;
-	}
-
-
-	/**
-	 * Appends the file handler to the list and returns it.
-	 *
-	 * @param fileHandlerCallback  File handler for processing.
-	 * @param timeoutMillis        Timeout waiting for the file creation in milliseconds.
-	 * @param fileLengthCheckDelay Timeout waiting for the file writing in milliseconds.
-	 * @return Instance of the file handler.
-	 */
-	public WatchItem append(FileHandlerCallback fileHandlerCallback, long timeoutMillis, long fileLengthCheckDelay) {
-		if (Objects.nonNull(handlerDao)) {
-			handlerDao.upsert(new PersistentFileHandler(fileHandlerCallback, timeoutMillis, directoryName));
-		}
-		WatchItem item = new WatchItem(fileHandlerCallback, timeoutMillis, fileLengthCheckDelay);
-		synchronized (this) {
-			int index = Collections.binarySearch(list, item);
-			if (index < 0) {
-				index = -index;
-				if (index > list.size()) {
-					list.add(item);
-				} else {
-					list.add(index - 1, item);
-				}
-			} else {
-				LOGGER.warn("Handler for UUID {} for folder {} will be replaced. Old item is: {}",
-						fileHandlerCallback.getUUID(), directoryFullName, get(index));
-				list.set(index, item);
-			}
-		}
-		return item;
-	}
-
-	/**
-	 * Appends the file handler to the list for the existing file and returns it. If the file name
-	 * is <b>null</b> this means that file does not exist and equal to call method
-	 * {@link WatchItemList#append(FileHandlerCallback, long, long)}.
-	 *
-	 * @param fileHandlerCallback  File handler for processing.
-	 * @param timeoutMillis        Timeout waiting for the file creation in milliseconds.
-	 * @param fileLengthCheckDelay Timeout waiting for the file writing in milliseconds.
-	 * @param fileName             file name.
-	 * @return Instance of file handler.
-	 */
-	public WatchItem append(FileHandlerCallback fileHandlerCallback, long timeoutMillis, long fileLengthCheckDelay,
-							String fileName) {
-		WatchItem item = append(fileHandlerCallback, timeoutMillis, fileLengthCheckDelay);
-		if (fileName != null) {
-			item.setFileName(fileName);
-		}
-		return item;
-	}
-
-	/**
-	 * Removes the file handler from list.
-	 *
-	 * @param index index of the file handler.
-	 */
-	public void remove(int index) {
-
-		final WatchItem watchItem = list.remove(index);
-		if (Objects.nonNull(handlerDao) && watchItem.getStatus() != ItemStatus.IS_FAILED) {
-			handlerDao.remove(watchItem.getFileHandlerCallback().getId());
-		}
-	}
-
-	/**
-	 * Returns the number of the file handlers in list.
-	 */
-	public int size() {
-		return list.size();
-	}
-
-	/**
-	 * Returns the file handler.
-	 *
-	 * @param index index of the file handler.
-	 */
-	public WatchItem get(int index) {
-		return list.get(index);
-	}
-
-	/**
-	 * Returns the index of the file handler in the list if it is contained in the list,
-	 * otherwise returns (-(insertion point) - 1).
-	 *
-	 * @param uuid UUID of the file handler.
-	 */
-	public int getIndex(String uuid) {
-		uuidSearch = uuid;
-		return Collections.binarySearch(list, new WatchItem(handlerSearch, 0, 0));
-	}
-
-	/**
-	 * Returns the instance of the file handler if it contained in the list,
-	 * otherwise returns <b>null</b>.
-	 */
-	public WatchItem getItem(String fileName) {
-		String uuid = DockerCommands.extractUUID(fileName);
-		int index = getIndex(uuid);
-		if (index < 0) {
-			return null;
-		}
-		return get(index);
-	}
-
-	/**
-	 * Runs asynchronously the file handler in the {@link ForkJoinPool#commonPool()}.
-	 *
-	 * @param item the file handler.
-	 */
-	private void runAsync(WatchItem item) {
-		LOGGER.trace("Process file {} for folder {}", item.getFileName(), directoryFullName);
-		item.setFuture(CompletableFuture.supplyAsync(
-				new AsyncFileHandler(item.getFileName(), getDirectoryName(),
-						item.getFileHandlerCallback(), Duration.milliseconds(item.getFileLengthCheckDelay()))));
-	}
-
-	/**
-	 * Runs the file processing asynchronously if it have status {@link ItemStatus#FILE_CAPTURED} and returns
-	 * <b>true</b>,
-	 * otherwise <b>false</b>.
-	 *
-	 * @param item the file handler.
-	 */
-	public boolean processItem(WatchItem item) {
-		if (item.getStatus() == ItemStatus.FILE_CAPTURED) {
-			runAsync(item);
-			return true;
-		}
-
-		if (item.isExpired()) {
-			LOGGER.warn("Watch time has expired for UUID {} in folder {}", item.getFileHandlerCallback().getUUID(),
-					directoryFullName);
-		}
-		return false;
-	}
-
-	/**
-	 * Checks all the file handlers and runs the file processing for it if have status
-	 * {@link ItemStatus#FILE_CAPTURED}.
-	 */
-	public int processItemAll() {
-		int count = 0;
-		synchronized (list) {
-			for (int i = 0; i < size(); i++) {
-				WatchItem item = list.get(i);
-				if (item.getStatus() == ItemStatus.FILE_CAPTURED && processItem(item)) {
-					count++;
-				}
-			}
-		}
-		if (count > 0) {
-			LOGGER.trace("Starts processing {} files for folder {}", count, directoryName);
-		}
-		return count;
-	}
-
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/BackupCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/BackupCallbackHandler.java
deleted file mode 100644
index 193d4d7..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/BackupCallbackHandler.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.dto.backup.EnvBackupDTO;
-import com.epam.dlab.dto.backup.EnvBackupStatus;
-import com.epam.dlab.dto.backup.EnvBackupStatusDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.fasterxml.jackson.annotation.JacksonInject;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.core.Response;
-
-@Slf4j
-public class BackupCallbackHandler implements FileHandlerCallback {
-	private static final ObjectMapper MAPPER = new ObjectMapper()
-			.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
-	private static final String STATUS_FIELD = "status";
-	private static final String BACKUP_FILE_FIELD = "backup_file";
-	private static final String ERROR_MESSAGE_FIELD = "error_message";
-	@JsonProperty
-	private final String uuid;
-	@JsonProperty
-	private final EnvBackupDTO dto;
-	private final RESTService selfService;
-	@JsonProperty
-	private final String callbackUrl;
-	@JsonProperty
-	private final String user;
-
-	@JsonCreator
-	public BackupCallbackHandler(
-			@JacksonInject RESTService selfService,
-			@JsonProperty("callbackUrl") String callbackUrl, @JsonProperty("user") String user,
-			@JsonProperty("dto") EnvBackupDTO dto) {
-		this.selfService = selfService;
-		this.uuid = dto.getId();
-		this.callbackUrl = callbackUrl;
-		this.user = user;
-		this.dto = dto;
-	}
-
-	@Override
-	public String getUUID() {
-		return uuid;
-	}
-
-	@Override
-	public boolean checkUUID(String uuid) {
-		return this.uuid.equals(uuid);
-	}
-
-	@Override
-	public boolean handle(String fileName, byte[] content) throws Exception {
-		final String fileContent = new String(content);
-		log.debug("Got file {} while waiting for UUID {}, backup response: {}", fileName, uuid, fileContent);
-
-		final JsonNode jsonNode = MAPPER.readTree(fileContent);
-		final EnvBackupStatus status = EnvBackupStatus.fromValue(jsonNode.get(STATUS_FIELD).textValue());
-		EnvBackupStatusDTO envBackupStatusDTO;
-		if (EnvBackupStatus.CREATED == status) {
-			envBackupStatusDTO = buildBackupStatusDto(EnvBackupStatus.CREATED)
-					.withBackupFile(jsonNode.get(BACKUP_FILE_FIELD).textValue());
-		} else {
-			envBackupStatusDTO = buildBackupStatusDto(EnvBackupStatus.FAILED)
-					.withErrorMessage(jsonNode.get(ERROR_MESSAGE_FIELD).textValue());
-		}
-		selfServicePost(envBackupStatusDTO);
-		return EnvBackupStatus.CREATED == status;
-	}
-
-	private void selfServicePost(EnvBackupStatusDTO statusDTO) {
-		log.debug("Send post request to self service {} for UUID {}, object is {}", uuid, statusDTO);
-		try {
-			selfService.post(callbackUrl, statusDTO, Response.class);
-		} catch (Exception e) {
-			log.error("Send request or response error for UUID {}: {}", uuid, e.getLocalizedMessage(), e);
-			throw new DlabException("Send request or response error for UUID " + uuid + ": " + e.getLocalizedMessage()
-					, e);
-		}
-	}
-
-	@Override
-	public void handleError(String errorMessage) {
-		buildBackupStatusDto(EnvBackupStatus.FAILED)
-				.withErrorMessage(errorMessage);
-	}
-
-	@Override
-	public String getUser() {
-		return user;
-	}
-
-	protected EnvBackupStatusDTO buildBackupStatusDto(EnvBackupStatus status) {
-		return new EnvBackupStatusDTO()
-				.withRequestId(uuid)
-				.withEnvBackupDTO(dto)
-				.withStatus(status)
-				.withUser(user);
-	}
-
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/CheckInactivityCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/CheckInactivityCallbackHandler.java
deleted file mode 100644
index 6269c9f..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/CheckInactivityCallbackHandler.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.computational.CheckInactivityStatusDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.fasterxml.jackson.annotation.JacksonInject;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.inject.Singleton;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.core.Response;
-
-@Slf4j
-@Singleton
-public class CheckInactivityCallbackHandler implements FileHandlerCallback {
-	private static final ObjectMapper MAPPER = new ObjectMapper()
-			.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
-	private static final String STATUS_FIELD = "status";
-	private static final String ERROR_MESSAGE_FIELD = "error_message";
-	private static final String RESPONSE = "response";
-	private static final String OK_STATUS_STRING = "ok";
-	private static final String RESULT_NODE = "result";
-	@JsonProperty
-	private final String uuid;
-	private final RESTService selfService;
-	@JsonProperty
-	private final String callbackUrl;
-	@JsonProperty
-	private final String user;
-	@JsonProperty
-	private final String exploratoryName;
-	@JsonProperty
-	private final String computationalName;
-
-	@JsonCreator
-	public CheckInactivityCallbackHandler(@JacksonInject RESTService selfService,
-										  @JsonProperty("callbackUrl") String callbackUrl,
-										  @JsonProperty("user") String user, String uuid, String exploratoryName,
-										  String computationalName) {
-		this.selfService = selfService;
-		this.uuid = uuid;
-		this.callbackUrl = callbackUrl;
-		this.user = user;
-		this.exploratoryName = exploratoryName;
-		this.computationalName = computationalName;
-	}
-
-	public CheckInactivityCallbackHandler(RESTService selfService,
-										  String callbackUrl, String user, String uuid, String exploratoryName) {
-		this(selfService, callbackUrl, user, uuid, exploratoryName, null);
-	}
-
-	@Override
-	public String getUUID() {
-		return uuid;
-	}
-
-	@Override
-	public boolean checkUUID(String uuid) {
-		return this.uuid.equals(uuid);
-	}
-
-	@Override
-	@SuppressWarnings("unchecked")
-	public boolean handle(String fileName, byte[] content) throws Exception {
-		final String fileContent = new String(content);
-		log.debug("Got file {} while waiting for UUID {}, check inactivity resources response: {}", fileName, uuid,
-				fileContent);
-
-		final JsonNode treeNode = MAPPER.readTree(fileContent);
-		final String status = treeNode.get(STATUS_FIELD).textValue();
-		CheckInactivityStatusDTO checkInactivityStatusDTO = OK_STATUS_STRING.equals(status) ?
-				getOkStatusDto(treeNode) : getFailedStatusDto(treeNode.get(ERROR_MESSAGE_FIELD).textValue());
-		selfServicePost(checkInactivityStatusDTO);
-		return OK_STATUS_STRING.equals(status);
-	}
-
-	@Override
-	public void handleError(String errorMessage) {
-		log.error(errorMessage);
-		selfServicePost(getFailedStatusDto(errorMessage).withErrorMessage(errorMessage));
-	}
-
-	@Override
-	public String getUser() {
-		return user;
-	}
-
-	private CheckInactivityStatusDTO getOkStatusDto(JsonNode jsonNode) {
-		final CheckInactivityStatusDTO statusDTO = new CheckInactivityStatusDTO().withStatus(OK_STATUS_STRING)
-				.withRequestId(uuid);
-		statusDTO.setComputationalName(computationalName);
-		statusDTO.setExploratoryName(exploratoryName);
-		final long lastActivity = Long.parseLong(jsonNode.get(RESPONSE).get(RESULT_NODE).textValue());
-		statusDTO.setLastActivityUnixTime(lastActivity);
-		return statusDTO;
-	}
-
-	private CheckInactivityStatusDTO getFailedStatusDto(String errorMessage) {
-		return new CheckInactivityStatusDTO().withStatus(UserInstanceStatus.FAILED)
-				.withRequestId(uuid)
-				.withErrorMessage(errorMessage);
-	}
-
-	private void selfServicePost(CheckInactivityStatusDTO statusDTO) {
-		log.debug("Send post request to self service for UUID {}, object is {}", uuid, statusDTO);
-		try {
-			selfService.post(callbackUrl, statusDTO, Response.class);
-		} catch (Exception e) {
-			log.error("Send request or response error for UUID {}: {}", uuid, e.getLocalizedMessage(), e);
-			throw new DlabException("Send request or response error for UUID " + uuid + ": "
-					+ e.getLocalizedMessage(), e);
-		}
-	}
-
-}
-
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ComputationalCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ComputationalCallbackHandler.java
deleted file mode 100644
index 877cc5a..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ComputationalCallbackHandler.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.dto.ResourceURL;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.epam.dlab.dto.computational.ComputationalStatusDTO;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.fasterxml.jackson.annotation.JacksonInject;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.JsonNode;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-import java.time.Instant;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
-
-@Slf4j
-public class ComputationalCallbackHandler extends ResourceCallbackHandler<ComputationalStatusDTO> {
-	private static final String INSTANCE_ID_FIELD = "instance_id";
-	private static final String COMPUTATIONAL_ID_FIELD = "hostname";
-	private static final String COMPUTATIONAL_URL_FIELD = "computational_url";
-
-	@JsonProperty
-	private final ComputationalBase<?> dto;
-	private ComputationalConfigure computationalConfigure;
-
-	@JsonCreator
-	public ComputationalCallbackHandler(@JacksonInject ComputationalConfigure computationalConfigure,
-										@JacksonInject RESTService selfService,
-										@JsonProperty("action") DockerAction action,
-										@JsonProperty("uuid") String uuid,
-										@JsonProperty("dto") ComputationalBase<?> dto) {
-
-		super(selfService, dto.getCloudSettings().getIamUser(), uuid, action);
-		this.computationalConfigure = computationalConfigure;
-		this.dto = dto;
-	}
-
-	protected ComputationalBase<?> getDto() {
-		return dto;
-	}
-
-	@Override
-	protected String getCallbackURI() {
-		return ApiCallbacks.COMPUTATIONAL + ApiCallbacks.STATUS_URI;
-	}
-
-	@Override
-	protected ComputationalStatusDTO parseOutResponse(JsonNode resultNode, ComputationalStatusDTO baseStatus) {
-		if (resultNode == null) {
-			return baseStatus;
-		}
-		baseStatus.withComputationalUrl(extractUrl(resultNode));
-		baseStatus.withLastActivity(Date.from(Instant.now()));
-
-		if (DockerAction.CREATE == getAction()) {
-			baseStatus
-					.withInstanceId(instanceId(resultNode.get(INSTANCE_ID_FIELD)))
-					.withComputationalId(getTextValue(resultNode.get(COMPUTATIONAL_ID_FIELD)));
-			if (UserInstanceStatus.of(baseStatus.getStatus()) == UserInstanceStatus.RUNNING) {
-				baseStatus.withStatus(UserInstanceStatus.CONFIGURING);
-				computationalConfigure.configure(getUUID(), getDto());
-			}
-		}
-		return baseStatus;
-	}
-
-	@Override
-	protected ComputationalStatusDTO getBaseStatusDTO(UserInstanceStatus status) {
-		return super.getBaseStatusDTO(status)
-                .withExploratoryName(dto.getExploratoryName())
-                .withComputationalName(dto.getComputationalName())
-                .withProject(dto.getProject());
-	}
-
-	private String instanceId(JsonNode jsonNode) {
-		if (jsonNode != null && jsonNode.isArray()) {
-			return StreamSupport.stream(jsonNode.spliterator(), false)
-					.map(JsonNode::textValue)
-					.collect(Collectors.joining(";"));
-		} else {
-			return getTextValue(jsonNode);
-		}
-
-	}
-
-	private List<ResourceURL> extractUrl(JsonNode resultNode) {
-		final JsonNode nodeUrl = resultNode.get(COMPUTATIONAL_URL_FIELD);
-		return Optional.ofNullable(nodeUrl)
-				.map(this::getUrls)
-				.orElse(Collections.emptyList());
-	}
-
-	private List<ResourceURL> getUrls(JsonNode nodeUrl) {
-		try {
-			return mapper.readValue(nodeUrl.toString(), new TypeReference<List<ResourceURL>>() {
-			});
-		} catch (IOException e) {
-			log.warn("Cannot parse field {} for UUID {} in JSON", RESPONSE_NODE + "." + RESULT_NODE + "." +
-					COMPUTATIONAL_URL_FIELD, getUUID(), e);
-		}
-		return Collections.emptyList();
-	}
-}
-
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ComputationalConfigure.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ComputationalConfigure.java
deleted file mode 100644
index b2aee18..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ComputationalConfigure.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.CommandBuilder;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.folderlistener.FolderListenerExecutor;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.aws.computational.SparkComputationalCreateAws;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.epam.dlab.dto.gcp.computational.SparkComputationalCreateGcp;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Objects;
-
-import static com.epam.dlab.backendapi.core.commands.DockerAction.CONFIGURE;
-
-@Slf4j
-@Singleton
-public class ComputationalConfigure implements DockerCommands {
-	@Inject
-	private ProvisioningServiceApplicationConfiguration configuration;
-	@Inject
-	private FolderListenerExecutor folderListenerExecutor;
-	@Inject
-	private ICommandExecutor commandExecutor;
-	@Inject
-	private CommandBuilder commandBuilder;
-	@Inject
-	private RESTService selfService;
-
-	public String configure(String uuid, ComputationalBase<?> dto) {
-		switch (configuration.getCloudProvider()) {
-			case AWS:
-				if (dto instanceof SparkComputationalCreateAws) {
-					return runConfigure(uuid, dto, DataEngineType.SPARK_STANDALONE);
-				} else {
-					return runConfigure(uuid, dto, DataEngineType.CLOUD_SERVICE);
-				}
-			case AZURE:
-				return runConfigure(uuid, dto, DataEngineType.SPARK_STANDALONE);
-			case GCP:
-				if (dto instanceof SparkComputationalCreateGcp) {
-					return runConfigure(uuid, dto, DataEngineType.SPARK_STANDALONE);
-				} else {
-					return runConfigure(uuid, dto, DataEngineType.CLOUD_SERVICE);
-				}
-
-			default:
-				throw new IllegalStateException(String.format("Wrong configuration of cloud provider %s %s",
-						configuration.getCloudProvider(), dto));
-		}
-	}
-
-	private String runConfigure(String uuid, ComputationalBase<?> dto, DataEngineType dataEngineType) {
-		log.debug("Configure computational resources {} for user {}: {}", dto.getComputationalName(), dto
-				.getEdgeUserName(), dto);
-		folderListenerExecutor.start(
-				configuration.getImagesDirectory(),
-				configuration.getResourceStatusPollTimeout(),
-				getFileHandlerCallback(CONFIGURE, uuid, dto));
-		try {
-			RunDockerCommand runDockerCommand = new RunDockerCommand()
-					.withInteractive()
-					.withName(nameContainer(dto.getEdgeUserName(), CONFIGURE,
-							dto.getExploratoryName(), dto.getComputationalName()))
-					.withVolumeForRootKeys(configuration.getKeyDirectory())
-					.withVolumeForResponse(configuration.getImagesDirectory())
-					.withVolumeForLog(configuration.getDockerLogDirectory(), dataEngineType.getName())
-					.withResource(dataEngineType.getName())
-					.withRequestId(uuid)
-					.withConfKeyName(configuration.getAdminKey())
-					.withActionConfigure(getImageConfigure(dto.getApplicationName(), dataEngineType));
-			if (configuration.getCloudProvider() == CloudProvider.AZURE &&
-					Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
-					!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
-				runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
-			}
-
-			commandExecutor.executeAsync(
-					dto.getEdgeUserName(),
-					uuid,
-					commandBuilder.buildCommand(runDockerCommand, dto));
-		} catch (Exception t) {
-			throw new DlabException("Could not configure computational resource cluster", t);
-		}
-		return uuid;
-	}
-
-	private FileHandlerCallback getFileHandlerCallback(DockerAction action, String originalUuid, ComputationalBase<?>
-			dto) {
-		return new ComputationalConfigureCallbackHandler(selfService, action, originalUuid, dto);
-	}
-
-	private String nameContainer(String user, DockerAction action, String exploratoryName, String name) {
-		return nameContainer(user, action.toString(), "computational", exploratoryName, name);
-	}
-
-	private String getImageConfigure(String application, DataEngineType dataEngineType) {
-		String imageName = DataEngineType.getDockerImageName(dataEngineType);
-		int pos = imageName.indexOf('-');
-		if (pos > 0) {
-			return imageName.substring(0, pos + 1) + application;
-		}
-		throw new DlabException("Could not describe the image name for computational resources from image " +
-				imageName + " and application " + application);
-	}
-
-	public String getResourceType() {
-		return Directories.DATA_ENGINE_SERVICE_LOG_DIRECTORY;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ComputationalConfigureCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ComputationalConfigureCallbackHandler.java
deleted file mode 100644
index 8d6e794..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ComputationalConfigureCallbackHandler.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.epam.dlab.dto.computational.ComputationalStatusDTO;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.fasterxml.jackson.annotation.JacksonInject;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonNode;
-
-import java.time.Instant;
-import java.util.Date;
-
-public class ComputationalConfigureCallbackHandler extends ResourceCallbackHandler<ComputationalStatusDTO> {
-
-	@JsonProperty
-	private final ComputationalBase<?> dto;
-
-	@JsonCreator
-	public ComputationalConfigureCallbackHandler(@JacksonInject RESTService selfService,
-												 @JsonProperty("action") DockerAction action,
-												 @JsonProperty("uuid") String uuid,
-												 @JsonProperty("dto") ComputationalBase<?> dto) {
-		super(selfService, dto.getCloudSettings().getIamUser(), uuid, action);
-		this.dto = dto;
-	}
-
-	@Override
-	protected String getCallbackURI() {
-		return ApiCallbacks.COMPUTATIONAL + ApiCallbacks.STATUS_URI;
-	}
-
-	@Override
-	protected ComputationalStatusDTO parseOutResponse(JsonNode resultNode, ComputationalStatusDTO baseStatus) {
-		return baseStatus
-				.withExploratoryName(dto.getExploratoryName())
-				.withComputationalName(dto.getComputationalName())
-				.withProject(dto.getProject())
-				.withUptime(null)
-				.withLastActivity(Date.from(Instant.now()));
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/EdgeCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/EdgeCallbackHandler.java
deleted file mode 100644
index d869e58..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/EdgeCallbackHandler.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-import com.epam.dlab.dto.base.keyload.UploadFileResult;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.fasterxml.jackson.annotation.JacksonInject;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonNode;
-
-import java.io.IOException;
-
-public class EdgeCallbackHandler<E extends EdgeInfo, T extends UploadFileResult<E>> extends ResourceCallbackHandler<T> {
-	@JsonProperty
-	private final String callbackURI;
-	@JsonProperty
-	private final Class<E> responseType;
-
-	@JsonCreator
-	public EdgeCallbackHandler(
-			@JacksonInject RESTService selfService, @JsonProperty("action") DockerAction action,
-			@JsonProperty("uuid") String uuid, @JsonProperty("user") String user,
-			@JsonProperty("callbackURI") String callbackURI,
-			@JsonProperty("responseType") Class<E> responseType,
-			@JsonProperty("resultType") Class<T> enclosingType) {
-
-		super(selfService, user, uuid, action, enclosingType);
-		this.callbackURI = callbackURI;
-		this.responseType = responseType;
-	}
-
-	@Override
-	protected String getCallbackURI() {
-		return callbackURI;
-	}
-
-	protected T parseOutResponse(JsonNode resultNode, T baseStatus) {
-		if (resultNode != null && getAction() == DockerAction.CREATE
-				&& UserInstanceStatus.of(baseStatus.getStatus()) != UserInstanceStatus.FAILED) {
-			try {
-				E credential = mapper.readValue(resultNode.toString(), responseType);
-				credential.setEdgeStatus(UserInstanceStatus.RUNNING.toString());
-				baseStatus.withEdgeInfo(credential);
-			} catch (IOException e) {
-				throw new DlabException("Cannot parse the EDGE info in JSON: " + e.getLocalizedMessage(), e);
-			}
-		}
-
-		return baseStatus;
-	}
-
-	@Override
-	public void handleError(String errorMessage) {
-		super.handleError("Could not upload the user key: " + errorMessage);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ExploratoryCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ExploratoryCallbackHandler.java
deleted file mode 100644
index 047ebf9..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ExploratoryCallbackHandler.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.dto.ResourceURL;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.exploratory.ExploratoryStatusDTO;
-import com.epam.dlab.rest.client.RESTService;
-import com.fasterxml.jackson.annotation.JacksonInject;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.JsonNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.List;
-
-import static com.epam.dlab.rest.contracts.ApiCallbacks.EXPLORATORY;
-import static com.epam.dlab.rest.contracts.ApiCallbacks.STATUS_URI;
-
-public class ExploratoryCallbackHandler extends ResourceCallbackHandler<ExploratoryStatusDTO> {
-	private static final Logger LOGGER = LoggerFactory.getLogger(ExploratoryCallbackHandler.class);
-
-	private static final String INSTANCE_ID_FIELD = "instance_id";
-	private static final String EXPLORATORY_ID_FIELD = "notebook_name";
-	private static final String EXPLORATORY_PRIVATE_IP_FIELD = "ip";
-	private static final String EXPLORATORY_URL_FIELD = "exploratory_url";
-	private static final String EXPLORATORY_USER_FIELD = "exploratory_user";
-	private static final String EXPLORATORY_PASSWORD_FIELD = "exploratory_pass";
-
-	@JsonProperty
-	private final String exploratoryName;
-	private final String project;
-
-	@JsonCreator
-	public ExploratoryCallbackHandler(@JacksonInject RESTService selfService,
-									  @JsonProperty("action") DockerAction action,
-									  @JsonProperty("uuid") String uuid, @JsonProperty("user") String user,
-									  String project, @JsonProperty("exploratoryName") String exploratoryName) {
-		super(selfService, user, uuid, action);
-		this.exploratoryName = exploratoryName;
-		this.project = project;
-	}
-
-	@Override
-	protected String getCallbackURI() {
-		return EXPLORATORY + STATUS_URI;
-	}
-
-	@Override
-	protected ExploratoryStatusDTO parseOutResponse(JsonNode resultNode, ExploratoryStatusDTO baseStatus) {
-		if (resultNode == null) {
-			return baseStatus;
-		}
-		final JsonNode nodeUrl = resultNode.get(EXPLORATORY_URL_FIELD);
-		List<ResourceURL> url = null;
-		if (nodeUrl != null) {
-			try {
-				url = mapper.readValue(nodeUrl.toString(), new TypeReference<List<ResourceURL>>() {
-				});
-			} catch (IOException e) {
-				LOGGER.warn("Cannot parse field {} for UUID {} in JSON",
-						RESPONSE_NODE + "." + RESULT_NODE + "." + EXPLORATORY_URL_FIELD, getUUID(), e);
-			}
-		}
-
-		String exploratoryId = getTextValue(resultNode.get(EXPLORATORY_ID_FIELD));
-		if (getAction() == DockerAction.CREATE && exploratoryId == null) {
-			LOGGER.warn("Empty field {} for UUID {} in JSON", String.format("%s.%s.%s", RESPONSE_NODE, RESULT_NODE,
-					EXPLORATORY_ID_FIELD), getUUID());
-		}
-
-		return baseStatus
-				.withInstanceId(getTextValue(resultNode.get(INSTANCE_ID_FIELD)))
-				.withExploratoryId(exploratoryId)
-				.withExploratoryUrl(url)
-				.withPrivateIp(getTextValue(resultNode.get(EXPLORATORY_PRIVATE_IP_FIELD)))
-				.withExploratoryUser(getTextValue(resultNode.get(EXPLORATORY_USER_FIELD)))
-				.withExploratoryPassword(getTextValue(resultNode.get(EXPLORATORY_PASSWORD_FIELD)));
-	}
-
-	@Override
-	protected ExploratoryStatusDTO getBaseStatusDTO(UserInstanceStatus status) {
-		return super.getBaseStatusDTO(status)
-				.withExploratoryName(exploratoryName)
-				.withProject(project);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ExploratoryGitCredsCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ExploratoryGitCredsCallbackHandler.java
deleted file mode 100644
index b6857e5..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ExploratoryGitCredsCallbackHandler.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.exploratory.ExploratoryStatusDTO;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.fasterxml.jackson.annotation.JacksonInject;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonNode;
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-public class ExploratoryGitCredsCallbackHandler extends ResourceCallbackHandler<ExploratoryStatusDTO> {
-
-	@JsonProperty
-	private final String exploratoryName;
-
-	@JsonCreator
-	public ExploratoryGitCredsCallbackHandler(@JacksonInject RESTService selfService,
-											  @JsonProperty("action") DockerAction action,
-											  @JsonProperty("uuid") String uuid,
-											  @JsonProperty("user") String user,
-											  @JsonProperty("exploratoryName") String exploratoryName) {
-		super(selfService, user, uuid, action);
-		this.exploratoryName = exploratoryName;
-	}
-
-	@Override
-	protected String getCallbackURI() {
-		return ApiCallbacks.GIT_CREDS;
-	}
-
-	@Override
-	protected ExploratoryStatusDTO parseOutResponse(JsonNode resultNode, ExploratoryStatusDTO baseStatus) {
-		log.trace("Parse GIT Creds: {}", resultNode);
-		return baseStatus;
-	}
-
-	@Override
-	protected ExploratoryStatusDTO getBaseStatusDTO(UserInstanceStatus status) {
-		return super.getBaseStatusDTO(status)
-				.withExploratoryName(exploratoryName);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ImageCreateCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ImageCreateCallbackHandler.java
deleted file mode 100644
index dbbc535..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ImageCreateCallbackHandler.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.exploratory.ExploratoryImageDTO;
-import com.epam.dlab.dto.exploratory.ImageCreateStatusDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.fasterxml.jackson.annotation.JacksonInject;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonNode;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-
-@Slf4j
-public class ImageCreateCallbackHandler extends ResourceCallbackHandler<ImageCreateStatusDTO> {
-	@JsonProperty
-	private final String imageName;
-	@JsonProperty
-	private final String exploratoryName;
-	@JsonProperty
-	private final String project;
-	@JsonProperty
-	private final String endpoint;
-
-	public ImageCreateCallbackHandler(RESTService selfService, String uuid, DockerAction action,
-			ExploratoryImageDTO image) {
-		super(selfService, image.getCloudSettings().getIamUser(), uuid, action);
-		this.imageName = image.getImageName();
-		this.exploratoryName = image.getExploratoryName();
-		this.project = image.getProject();
-		this.endpoint = image.getEndpoint();
-	}
-
-	@JsonCreator
-	private ImageCreateCallbackHandler(
-			@JacksonInject RESTService selfService, @JsonProperty("uuid") String uuid,
-			@JsonProperty("action") DockerAction action,
-			@JsonProperty("user") String user,
-			@JsonProperty("imageName") String imageName,
-			@JsonProperty("exploratoryName") String exploratoryName,
-			@JsonProperty("project") String projectName,
-			@JsonProperty("endpoint") String endpoint) {
-		super(selfService, user, uuid, action);
-		this.imageName = imageName;
-		this.exploratoryName = exploratoryName;
-		this.project = projectName;
-		this.endpoint = endpoint;
-	}
-
-	@Override
-	protected String getCallbackURI() {
-		return ApiCallbacks.IMAGE_STATUS_URI;
-	}
-
-	@Override
-	protected ImageCreateStatusDTO parseOutResponse(JsonNode document, ImageCreateStatusDTO statusDTO) {
-		if (document != null) {
-			statusDTO.withImageCreateDto(toImageCreateDto(document.toString()));
-		}
-		return statusDTO;
-	}
-
-	@Override
-	protected ImageCreateStatusDTO getBaseStatusDTO(UserInstanceStatus status) {
-		final ImageCreateStatusDTO statusDTO = super.getBaseStatusDTO(status);
-		statusDTO.setExploratoryName(exploratoryName);
-		statusDTO.setName(imageName);
-		statusDTO.setProject(project);
-		statusDTO.setEndpoint(endpoint);
-		statusDTO.withoutImageCreateDto();
-		return statusDTO;
-	}
-
-	private ImageCreateStatusDTO.ImageCreateDTO toImageCreateDto(String content) {
-		try {
-			return mapper.readValue(content, ImageCreateStatusDTO.ImageCreateDTO.class);
-		} catch (IOException e) {
-			log.error("Can't parse create image response with content {} for uuid {}", content, getUUID());
-			throw new DlabException(String.format("Can't parse create image response with content %s for uuid %s",
-					content, getUUID()), e);
-		}
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/LibInstallCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/LibInstallCallbackHandler.java
deleted file mode 100644
index 8d46b60..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/LibInstallCallbackHandler.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.exploratory.LibInstallDTO;
-import com.epam.dlab.dto.exploratory.LibInstallStatusDTO;
-import com.epam.dlab.dto.exploratory.LibraryInstallDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.fasterxml.jackson.annotation.JacksonInject;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.JsonNode;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-import java.time.Instant;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Handler of docker response for the request for libraries installation.
- */
-@Slf4j
-public class LibInstallCallbackHandler extends ResourceCallbackHandler<LibInstallStatusDTO> {
-
-	/**
-	 * Name of node in response "Libs".
-	 */
-	private static final String LIBS = "Libs";
-
-	/**
-	 * Full name of node in response "Libs".
-	 */
-	private static final String LIBS_ABSOLUTE_PATH = RESPONSE_NODE + "." + RESULT_NODE + "." + LIBS;
-
-	/**
-	 * Exploratory DTO.
-	 */
-	@JsonProperty
-	private final LibraryInstallDTO dto;
-
-	/**
-	 * Instantiate handler for process of docker response for libraries installation.
-	 *
-	 * @param selfService REST pointer for Self Service.
-	 * @param action      docker action.
-	 * @param uuid        request UID.
-	 * @param dto         contains libraries to instal
-	 */
-	@JsonCreator
-	public LibInstallCallbackHandler(
-			@JacksonInject RESTService selfService,
-			@JsonProperty("action") DockerAction action,
-			@JsonProperty("uuid") String uuid, @JsonProperty("user") String user,
-			@JsonProperty("dto") LibraryInstallDTO dto) {
-		super(selfService, user, uuid, action);
-		this.dto = dto;
-	}
-
-	@Override
-	protected String getCallbackURI() {
-		return ApiCallbacks.LIB_STATUS_URI;
-	}
-
-	@Override
-	protected LibInstallStatusDTO parseOutResponse(JsonNode resultNode, LibInstallStatusDTO status) {
-
-		if (UserInstanceStatus.FAILED == UserInstanceStatus.of(status.getStatus()) || resultNode == null) {
-			throw new DlabException("Can't handle response result node is null or response status is failed");
-		}
-
-		JsonNode nodeLibs = resultNode.get(LIBS);
-		if (nodeLibs == null) {
-			throw new DlabException("Can't handle response without property " + LIBS_ABSOLUTE_PATH);
-		}
-		try {
-			final List<LibInstallDTO> libs = mapper.readValue(nodeLibs.toString(),
-					new TypeReference<List<LibInstallDTO>>() {
-					});
-			status.withLibs(libs);
-		} catch (IOException e) {
-			log.warn("Can't parse field {} for UUID {} in JSON", LIBS_ABSOLUTE_PATH, getUUID(), e);
-		}
-
-		return status;
-	}
-
-	@Override
-	protected LibInstallStatusDTO getBaseStatusDTO(UserInstanceStatus status) {
-		return super.getBaseStatusDTO(status)
-				.withExploratoryName(dto.getExploratoryName())
-				.withComputationalName(dto.getComputationalName())
-				.withProject(dto.getProject())
-				.withUptime(Date.from(Instant.now()));
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/LibListCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/LibListCallbackHandler.java
deleted file mode 100644
index b1b302c..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/LibListCallbackHandler.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.exploratory.LibListStatusDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.fasterxml.jackson.annotation.JacksonInject;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonNode;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-/**
- * Handler of docker response for the request the list of libraries.
- */
-public class LibListCallbackHandler extends ResourceCallbackHandler<LibListStatusDTO> {
-
-	/**
-	 * Name of node in response "file".
-	 */
-	private static final String FILE = "file";
-
-	/**
-	 * The name of docker image.
-	 */
-	@JsonProperty
-	private final String group;
-
-	/**
-	 * Instantiate handler for process of docker response for list of libraries.
-	 *
-	 * @param selfService REST pointer for Self Service.
-	 * @param action      docker action.
-	 * @param uuid        request UID.
-	 * @param user        the name of user.
-	 * @param group       the name of a group.
-	 */
-	@JsonCreator
-	public LibListCallbackHandler(
-			@JacksonInject RESTService selfService, @JsonProperty("action") DockerAction action,
-			@JsonProperty("uuid") String uuid, @JsonProperty("user") String user,
-			@JsonProperty("group") String group) {
-		super(selfService, user, uuid, action);
-		this.group = group;
-	}
-
-	@Override
-	protected String getCallbackURI() {
-		return ApiCallbacks.UPDATE_LIBS_URI;
-	}
-
-	@Override
-	protected LibListStatusDTO parseOutResponse(JsonNode resultNode, LibListStatusDTO status) {
-		if (UserInstanceStatus.FAILED == UserInstanceStatus.of(status.getStatus())) {
-			return status;
-		}
-		if (resultNode == null) {
-			throw new DlabException("Can't handle response result node is null");
-		}
-
-		JsonNode resultFileNode = resultNode.get(FILE);
-		if (resultFileNode == null) {
-			throw new DlabException("Can't handle response without property " + FILE);
-		}
-
-		Path path = Paths.get(resultFileNode.asText()).toAbsolutePath();
-		if (path.toFile().exists()) {
-			try {
-				status.withLibs(new String(Files.readAllBytes(path)));
-				Files.delete(path);
-				return status;
-			} catch (IOException e) {
-				throw new DlabException("Can't read file " + path + " : " + e.getLocalizedMessage(), e);
-			}
-		} else {
-			throw new DlabException("Can't handle response. The file " + path + " does not exist");
-		}
-	}
-
-	@Override
-	protected LibListStatusDTO getBaseStatusDTO(UserInstanceStatus status) {
-		return super.getBaseStatusDTO(status)
-				.withGroup(group);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/PersistentFileHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/PersistentFileHandler.java
deleted file mode 100644
index 6cac2db..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/PersistentFileHandler.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-public final class PersistentFileHandler {
-
-	private final FileHandlerCallback handler;
-	private final long timeout;
-	private final String directory;
-
-	@JsonCreator
-	public PersistentFileHandler(@JsonProperty("handler") FileHandlerCallback handler, @JsonProperty("timeout")
-			long timeout, @JsonProperty("directory") String directory) {
-		this.handler = handler;
-		this.timeout = timeout;
-		this.directory = directory;
-	}
-
-	public FileHandlerCallback getHandler() {
-		return handler;
-	}
-
-	public long getTimeout() {
-		return timeout;
-	}
-
-	public String getDirectory() {
-		return directory;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ProjectCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ProjectCallbackHandler.java
deleted file mode 100644
index fa41998..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ProjectCallbackHandler.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-import com.epam.dlab.dto.base.project.ProjectResult;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.fasterxml.jackson.databind.JsonNode;
-
-import java.io.IOException;
-
-public class ProjectCallbackHandler extends ResourceCallbackHandler<ProjectResult> {
-
-
-	private final String callbackUri;
-	private final String projectName;
-	private final Class<? extends EdgeInfo> clazz;
-	private final String endpointName;
-
-	public ProjectCallbackHandler(RESTService selfService, String user,
-	                              String uuid, DockerAction action, String callbackUri, String projectName,
-	                              Class<? extends EdgeInfo> clazz, String endpointName) {
-		super(selfService, user, uuid, action);
-		this.callbackUri = callbackUri;
-		this.projectName = projectName;
-		this.clazz = clazz;
-		this.endpointName = endpointName;
-	}
-
-	@Override
-	protected String getCallbackURI() {
-		return callbackUri;
-	}
-
-	@Override
-	protected ProjectResult parseOutResponse(JsonNode resultNode, ProjectResult baseStatus) {
-		baseStatus.setProjectName(projectName);
-		baseStatus.setEndpointName(endpointName);
-		if (resultNode != null && getAction() == DockerAction.CREATE
-				&& UserInstanceStatus.of(baseStatus.getStatus()) != UserInstanceStatus.FAILED) {
-			try {
-				final EdgeInfo projectEdgeInfo = mapper.readValue(resultNode.toString(), clazz);
-				baseStatus.setEdgeInfo(projectEdgeInfo);
-			} catch (IOException e) {
-				throw new DlabException("Cannot parse the EDGE info in JSON: " + e.getLocalizedMessage(), e);
-			}
-		}
-
-		return baseStatus;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ResourceCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ResourceCallbackHandler.java
deleted file mode 100644
index 6bc1466..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ResourceCallbackHandler.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.dto.StatusBaseDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.lang.reflect.ParameterizedType;
-import java.time.Instant;
-import java.util.Date;
-
-public abstract class ResourceCallbackHandler<T extends StatusBaseDTO<?>> implements FileHandlerCallback {
-	private static final Logger log = LoggerFactory.getLogger(ResourceCallbackHandler.class);
-	final ObjectMapper mapper = new ObjectMapper().configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
-
-	private static final String STATUS_FIELD = "status";
-	protected static final String RESPONSE_NODE = "response";
-	protected static final String RESULT_NODE = "result";
-	private static final String ERROR_NODE = "error";
-
-	private static final String OK_STATUS = "ok";
-
-	@JsonIgnore
-	private final RESTService selfService;
-	@JsonProperty
-	private final String user;
-	@JsonProperty
-	private final String uuid;
-	@JsonProperty
-	private final DockerAction action;
-	@JsonProperty
-	private final Class<T> resultType;
-
-	@SuppressWarnings("unchecked")
-	public ResourceCallbackHandler(RESTService selfService, String user,
-								   String uuid, DockerAction action) {
-		this.selfService = selfService;
-		this.user = user;
-		this.uuid = uuid;
-		this.action = action;
-		this.resultType =
-				(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
-	}
-
-	public ResourceCallbackHandler(RESTService selfService, String user,
-								   String uuid,
-								   DockerAction action,
-								   Class<T> resultType) {
-		this.selfService = selfService;
-		this.user = user;
-		this.uuid = uuid;
-		this.action = action;
-		this.resultType = resultType;
-	}
-
-	@Override
-	public String getUUID() {
-		return uuid;
-	}
-
-	@Override
-	public boolean checkUUID(String uuid) {
-		return this.uuid.equals(uuid);
-	}
-
-	@Override
-	public String getUser() {
-		return user;
-	}
-
-	public DockerAction getAction() {
-		return action;
-	}
-
-	private void selfServicePost(T object) {
-		debugMessage("Send post request to self service {} for UUID {}, object is {}",
-				getCallbackURI(), uuid, object);
-		try {
-			selfService.post(getCallbackURI(), object, resultType);
-		} catch (Exception e) {
-			log.error("Send request or response error for UUID {}: {}", uuid, e.getLocalizedMessage(), e);
-			throw new DlabException("Send request or responce error for UUID " + uuid + ": " + e.getLocalizedMessage()
-					, e);
-		}
-	}
-
-	@Override
-	public boolean handle(String fileName, byte[] content) throws Exception {
-		debugMessage("Got file {} while waiting for UUID {}, for action {}, docker response: {}",
-				fileName, uuid, action.name(), new String(content));
-		JsonNode document = mapper.readTree(content);
-		boolean success = isSuccess(document);
-		UserInstanceStatus status = calcStatus(action, success);
-		T result = getBaseStatusDTO(status);
-
-		JsonNode resultNode = document.get(RESPONSE_NODE).get(RESULT_NODE);
-		if (success) {
-			debugMessage("Did {} resource for user: {}, UUID: {}", action, user, uuid);
-		} else {
-			log.error("Could not {} resource for user: {}, UUID: {}", action, user, uuid);
-			result.setErrorMessage(getTextValue(resultNode.get(ERROR_NODE)));
-		}
-		result = parseOutResponse(resultNode, result);
-
-		selfServicePost(result);
-		return !UserInstanceStatus.FAILED.equals(status);
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public void handleError(String errorMessage) {
-		try {
-			selfServicePost((T) getBaseStatusDTO(UserInstanceStatus.FAILED)
-					.withErrorMessage(errorMessage));
-		} catch (Exception t) {
-			throw new DlabException("Could not send error message to Self Service for UUID " + uuid + ", user " + user + ": " + errorMessage, t);
-		}
-	}
-
-	protected abstract String getCallbackURI();
-
-	protected abstract T parseOutResponse(JsonNode document, T baseStatus);
-
-	@SuppressWarnings("unchecked")
-	protected T getBaseStatusDTO(UserInstanceStatus status) {
-		try {
-			return (T) resultType.newInstance()
-					.withRequestId(uuid)
-					.withUser(user)
-					.withStatus(status)
-					.withUptime(getUptime(status));
-		} catch (Exception t) {
-			throw new DlabException("Something went wrong", t);
-		}
-	}
-
-	private boolean isSuccess(JsonNode document) {
-		return OK_STATUS.equals(document.get(STATUS_FIELD).textValue());
-	}
-
-	private UserInstanceStatus calcStatus(DockerAction action, boolean success) {
-		if (success) {
-			switch (action) {
-				case STATUS:
-				case GIT_CREDS:
-				case LIB_LIST:
-				case LIB_INSTALL:
-				case CREATE_IMAGE:
-					return UserInstanceStatus.CREATED; // Any status besides failed
-				case CREATE:
-				case CONFIGURE:
-				case START:
-				case RECONFIGURE_SPARK:
-					return UserInstanceStatus.RUNNING;
-				case STOP:
-					return UserInstanceStatus.STOPPED;
-				case TERMINATE:
-					return UserInstanceStatus.TERMINATED;
-				default:
-					break;
-			}
-		}
-		return UserInstanceStatus.FAILED;
-	}
-
-	protected Date getUptime(UserInstanceStatus status) {
-		return UserInstanceStatus.RUNNING == status ? Date.from(Instant.now()) : null;
-	}
-
-	protected String getTextValue(JsonNode jsonNode) {
-		return jsonNode != null ? jsonNode.textValue() : null;
-	}
-
-	private void debugMessage(String format, Object... arguments) {
-		if (action == DockerAction.STATUS) {
-			log.trace(format, arguments);
-		} else {
-			log.debug(format, arguments);
-		}
-	}
-
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ResourcesStatusCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ResourcesStatusCallbackHandler.java
deleted file mode 100644
index d2a9d31..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ResourcesStatusCallbackHandler.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.dto.status.EnvResourceList;
-import com.epam.dlab.dto.status.EnvStatusDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.fasterxml.jackson.annotation.JacksonInject;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonNode;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-import java.time.Instant;
-import java.util.Date;
-
-import static com.epam.dlab.rest.contracts.ApiCallbacks.INFRASTRUCTURE;
-import static com.epam.dlab.rest.contracts.ApiCallbacks.STATUS_URI;
-
-@Slf4j
-public class ResourcesStatusCallbackHandler extends ResourceCallbackHandler<EnvStatusDTO> {
-
-	@JsonCreator
-	public ResourcesStatusCallbackHandler(
-			@JacksonInject RESTService selfService, @JsonProperty("action") DockerAction
-			action, @JsonProperty("uuid") String uuid, @JsonProperty("user") String user) {
-		super(selfService, user, uuid, action);
-	}
-
-	@Override
-	protected String getCallbackURI() {
-		return INFRASTRUCTURE + STATUS_URI;
-	}
-
-	@Override
-	protected EnvStatusDTO parseOutResponse(JsonNode resultNode, EnvStatusDTO baseStatus) {
-		if (resultNode == null) {
-			return baseStatus;
-		}
-
-		EnvResourceList resourceList;
-		try {
-			resourceList = mapper.readValue(resultNode.toString(), EnvResourceList.class);
-		} catch (IOException e) {
-			throw new DlabException("Docker response for UUID " + getUUID() + " not valid: " + e.getLocalizedMessage()
-					, e);
-		}
-
-		baseStatus.withResourceList(resourceList)
-				.withUptime(Date.from(Instant.now()));
-
-		log.trace("Inner status {}", baseStatus);
-
-		return baseStatus;
-	}
-
-	@Override
-	public boolean handle(String fileName, byte[] content) throws Exception {
-		try {
-			return super.handle(fileName, content);
-		} catch (Exception e) {
-			log.warn("Could not retrive the status of resources for UUID {} and user {}: {}",
-					getUUID(), getUser(), e.getLocalizedMessage(), e);
-		}
-		return true; // Always necessary return true for status response
-	}
-
-	@Override
-	public void handleError(String errorMessage) {
-		// Nothing action for status response
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ReuploadKeyCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ReuploadKeyCallbackHandler.java
deleted file mode 100644
index 16c9814..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ReuploadKeyCallbackHandler.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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.core.response.handlers;
-
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyCallbackDTO;
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyStatus;
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyStatusDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.fasterxml.jackson.annotation.JacksonInject;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.core.Response;
-
-@Slf4j
-public class ReuploadKeyCallbackHandler implements FileHandlerCallback {
-	private static final ObjectMapper MAPPER = new ObjectMapper()
-			.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
-	private static final String STATUS_FIELD = "status";
-	private static final String ERROR_MESSAGE_FIELD = "error_message";
-	@JsonProperty
-	private final String uuid;
-	@JsonProperty
-	private final ReuploadKeyCallbackDTO dto;
-	private final RESTService selfService;
-	@JsonProperty
-	private final String callbackUrl;
-	@JsonProperty
-	private final String user;
-
-	@JsonCreator
-	public ReuploadKeyCallbackHandler(@JacksonInject RESTService selfService,
-									  @JsonProperty("callbackUrl") String callbackUrl,
-									  @JsonProperty("user") String user,
-									  @JsonProperty("dto") ReuploadKeyCallbackDTO dto) {
-		this.selfService = selfService;
-		this.uuid = dto.getId();
-		this.callbackUrl = callbackUrl;
-		this.user = user;
-		this.dto = dto;
-	}
-
-	@Override
-	public String getUUID() {
-		return uuid;
-	}
-
-	@Override
-	public boolean checkUUID(String uuid) {
-		return this.uuid.equals(uuid);
-	}
-
-	@Override
-	public boolean handle(String fileName, byte[] content) throws Exception {
-		final String fileContent = new String(content);
-		log.debug("Got file {} while waiting for UUID {}, reupload key response: {}", fileName, uuid, fileContent);
-
-		final JsonNode jsonNode = MAPPER.readTree(fileContent);
-		final String status = jsonNode.get(STATUS_FIELD).textValue();
-		ReuploadKeyStatusDTO reuploadKeyStatusDTO;
-		if ("ok".equals(status)) {
-			reuploadKeyStatusDTO = buildReuploadKeyStatusDto(ReuploadKeyStatus.COMPLETED);
-		} else {
-			reuploadKeyStatusDTO = buildReuploadKeyStatusDto(ReuploadKeyStatus.FAILED)
-					.withErrorMessage(jsonNode.get(ERROR_MESSAGE_FIELD).textValue());
-		}
-		selfServicePost(reuploadKeyStatusDTO);
-		return "ok".equals(status);
-	}
-
-	private void selfServicePost(ReuploadKeyStatusDTO statusDTO) {
-		log.debug("Send post request to self service for UUID {}, object is {}", uuid, statusDTO);
-		try {
-			selfService.post(callbackUrl, statusDTO, Response.class);
-		} catch (Exception e) {
-			log.error("Send request or response error for UUID {}: {}", uuid, e.getLocalizedMessage(), e);
-			throw new DlabException("Send request or response error for UUID " + uuid + ": "
-					+ e.getLocalizedMessage(), e);
-		}
-	}
-
-	@Override
-	public void handleError(String errorMessage) {
-		buildReuploadKeyStatusDto(ReuploadKeyStatus.FAILED)
-				.withErrorMessage(errorMessage);
-	}
-
-	@Override
-	public String getUser() {
-		return user;
-	}
-
-	private ReuploadKeyStatusDTO buildReuploadKeyStatusDto(ReuploadKeyStatus status) {
-		return new ReuploadKeyStatusDTO()
-				.withRequestId(uuid)
-				.withReuploadKeyCallbackDto(dto)
-				.withReuploadKeyStatus(status)
-				.withUser(user);
-	}
-
-}
-
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/dao/CallbackHandlerDao.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/dao/CallbackHandlerDao.java
deleted file mode 100644
index 02fccfa..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/dao/CallbackHandlerDao.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.core.response.handlers.dao;
-
-import com.epam.dlab.backendapi.core.response.handlers.PersistentFileHandler;
-
-import java.util.List;
-
-public interface CallbackHandlerDao {
-
-	void upsert(PersistentFileHandler handlerCallback);
-
-	List<PersistentFileHandler> findAll();
-
-	void remove(String handlerId);
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/dao/FileSystemCallbackHandlerDao.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/dao/FileSystemCallbackHandlerDao.java
deleted file mode 100644
index 268950a..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/dao/FileSystemCallbackHandlerDao.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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.core.response.handlers.dao;
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.response.handlers.PersistentFileHandler;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.util.FileUtils;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Stream;
-
-import static java.util.stream.Collectors.toList;
-
-@Singleton
-@Slf4j
-public class FileSystemCallbackHandlerDao implements CallbackHandlerDao {
-
-	@Inject
-	private ProvisioningServiceApplicationConfiguration configuration;
-	@Inject
-	private ObjectMapper mapper;
-
-	@Override
-	public void upsert(PersistentFileHandler handlerCallback) {
-		removeWithUUID(handlerCallback.getHandler().getUUID());
-		final String fileName = fileName(handlerCallback.getHandler().getId());
-		final String absolutePath = getAbsolutePath(fileName);
-		saveToFile(handlerCallback, fileName, absolutePath);
-	}
-
-	@Override
-	public List<PersistentFileHandler> findAll() {
-		try (final Stream<Path> pathStream = Files.list(Paths.get(configuration.getHandlerDirectory()))) {
-			return pathStream.map(this::toPersistentFileHandler)
-					.filter(Optional::isPresent)
-					.map(Optional::get)
-					.collect(toList());
-		} catch (IOException e) {
-			log.error("Can not restore handlers due to: {}", e.getMessage(), e);
-		}
-		return Collections.emptyList();
-	}
-
-	@Override
-	public void remove(String handlerId) {
-		try {
-			Files.delete(Paths.get(getAbsolutePath(fileName(handlerId))));
-		} catch (Exception e) {
-			log.error("Can not remove handler {} due to: {}", handlerId, e.getMessage(), e);
-			throw new DlabException("Can not remove handler " + handlerId + " due to: " + e.getMessage());
-		}
-	}
-
-	private void removeWithUUID(String uuid) {
-		try (final Stream<Path> pathStream = Files.list(Paths.get(configuration.getHandlerDirectory()))) {
-			pathStream.map(Path::toString)
-					.filter(path -> path.contains(uuid))
-					.findAny()
-					.ifPresent(FileUtils::deleteFile);
-		} catch (IOException e) {
-			log.error("Problem occurred with accessing directory {} due to: {}", configuration.getHandlerDirectory(),
-					e.getLocalizedMessage(), e);
-		}
-	}
-
-	private String getAbsolutePath(String fileName) {
-		return configuration.getHandlerDirectory() + File.separator + fileName;
-	}
-
-	private void saveToFile(PersistentFileHandler handlerCallback, String fileName, String absolutePath) {
-		try {
-			log.trace("Persisting callback handler to file {}", absolutePath);
-			Files.write(Paths.get(absolutePath), mapper.writeValueAsBytes(handlerCallback), StandardOpenOption.CREATE);
-		} catch (Exception e) {
-			log.warn("Can not persist file handler {} due to {}", fileName, e.getMessage(), e);
-		}
-	}
-
-	private String fileName(String handlerId) {
-		return handlerId + ".json";
-	}
-
-	private Optional<PersistentFileHandler> toPersistentFileHandler(Path path) {
-		try {
-			return Optional.of(mapper.readValue(path.toFile(), PersistentFileHandler.class));
-		} catch (Exception e) {
-			log.warn("Can not deserialize file handler from file: {}", path.toString(), e);
-		}
-		return Optional.empty();
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/AwsProvisioningModule.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/AwsProvisioningModule.java
deleted file mode 100644
index 70e7966..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/AwsProvisioningModule.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.modules;
-
-import com.epam.dlab.backendapi.resources.aws.ComputationalResourceAws;
-import com.epam.dlab.backendapi.resources.aws.EdgeResourceAws;
-import com.epam.dlab.backendapi.resources.aws.ExploratoryResourceAws;
-import com.epam.dlab.backendapi.resources.aws.InfrastructureResourceAws;
-import com.epam.dlab.cloud.CloudModule;
-import com.google.inject.Injector;
-import io.dropwizard.setup.Environment;
-
-public class AwsProvisioningModule extends CloudModule {
-
-    @Override
-    public void init(Environment environment, Injector injector) {
-        environment.jersey().register(injector.getInstance(EdgeResourceAws.class));
-        environment.jersey().register(injector.getInstance(InfrastructureResourceAws.class));
-        environment.jersey().register(injector.getInstance(ExploratoryResourceAws.class));
-        environment.jersey().register(injector.getInstance(ComputationalResourceAws.class));
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/AzureProvisioningModule.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/AzureProvisioningModule.java
deleted file mode 100644
index 3a2cdcc..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/AzureProvisioningModule.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.modules;
-
-import com.epam.dlab.backendapi.resources.azure.ComputationalResourceAzure;
-import com.epam.dlab.backendapi.resources.azure.EdgeResourceAzure;
-import com.epam.dlab.backendapi.resources.azure.ExploratoryResourceAzure;
-import com.epam.dlab.backendapi.resources.azure.InfrastructureResourceAzure;
-import com.epam.dlab.cloud.CloudModule;
-import com.google.inject.Injector;
-import io.dropwizard.setup.Environment;
-
-public class AzureProvisioningModule extends CloudModule {
-
-    @Override
-    public void init(Environment environment, Injector injector) {
-        environment.jersey().register(injector.getInstance(EdgeResourceAzure.class));
-        environment.jersey().register(injector.getInstance(InfrastructureResourceAzure.class));
-        environment.jersey().register(injector.getInstance(ExploratoryResourceAzure.class));
-        environment.jersey().register(injector.getInstance(ComputationalResourceAzure.class));
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/CloudModuleConfigurator.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/CloudModuleConfigurator.java
deleted file mode 100644
index aa86fd6..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/CloudModuleConfigurator.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.modules;
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.cloud.CloudModule;
-
-public class CloudModuleConfigurator {
-
-    private CloudModuleConfigurator() {
-    }
-
-    public static CloudModule getCloudModule(ProvisioningServiceApplicationConfiguration configuration) {
-        switch (configuration.getCloudProvider()) {
-            case AWS:
-                return new AwsProvisioningModule();
-            case AZURE:
-                return new AzureProvisioningModule();
-            case GCP:
-                return new GcpProvisioningModule();
-            default:
-                throw new UnsupportedOperationException("Unsupported cloud provider " + configuration.getCloudProvider());
-        }
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/GcpProvisioningModule.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/GcpProvisioningModule.java
deleted file mode 100644
index 4553592..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/GcpProvisioningModule.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.modules;
-
-import com.epam.dlab.backendapi.resources.gcp.ComputationalResourceGcp;
-import com.epam.dlab.backendapi.resources.gcp.EdgeResourceGcp;
-import com.epam.dlab.backendapi.resources.gcp.ExploratoryResourceGcp;
-import com.epam.dlab.backendapi.resources.gcp.InfrastructureResourceGcp;
-import com.epam.dlab.cloud.CloudModule;
-import com.google.inject.Injector;
-import io.dropwizard.setup.Environment;
-
-public class GcpProvisioningModule extends CloudModule {
-
-    @Override
-    public void init(Environment environment, Injector injector) {
-        environment.jersey().register(injector.getInstance(EdgeResourceGcp.class));
-        environment.jersey().register(injector.getInstance(InfrastructureResourceGcp.class));
-        environment.jersey().register(injector.getInstance(ExploratoryResourceGcp.class));
-        environment.jersey().register(injector.getInstance(ComputationalResourceGcp.class));
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ModuleFactory.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ModuleFactory.java
deleted file mode 100644
index 2141d2d..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ModuleFactory.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.modules;
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.google.inject.AbstractModule;
-import io.dropwizard.setup.Environment;
-
-public class ModuleFactory {
-
-    private ModuleFactory() {
-    }
-
-    /**
-     * Instantiates an application configuration of Provisioning Service for production or tests if
-     * the mock property of configuration is set to <b>true</b> and method {@link ProvisioningServiceApplicationConfiguration#isDevMode()}}
-     * returns <b>true</b> value.
-     *
-     * @param configuration application configuration of Provisioning Service.
-     * @param environment   environment of Provisioning Service.
-     */
-    public static AbstractModule getModule(ProvisioningServiceApplicationConfiguration configuration, Environment environment) {
-        return configuration.isDevMode()
-                ? new ProvisioningDevModule(configuration, environment)
-                : new ProductionModule(configuration, environment);
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
deleted file mode 100644
index 3aac3cd..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.modules;
-
-import com.epam.dlab.ModuleBase;
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.DockerWarmuper;
-import com.epam.dlab.backendapi.core.MetadataHolder;
-import com.epam.dlab.backendapi.core.commands.CommandExecutor;
-import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
-import com.epam.dlab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
-import com.epam.dlab.backendapi.core.response.handlers.dao.FileSystemCallbackHandlerDao;
-import com.epam.dlab.backendapi.service.BucketService;
-import com.epam.dlab.backendapi.service.CheckInactivityService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.backendapi.service.RestoreCallbackHandlerService;
-import com.epam.dlab.backendapi.service.impl.CheckInactivityServiceImpl;
-import com.epam.dlab.backendapi.service.impl.ProjectServiceImpl;
-import com.epam.dlab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
-import com.epam.dlab.backendapi.service.impl.aws.BucketServiceAwsImpl;
-import com.epam.dlab.backendapi.service.impl.azure.BucketServiceAzureImpl;
-import com.epam.dlab.backendapi.service.impl.gcp.BucketServiceGcpImpl;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.rest.client.RESTService;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.inject.name.Names;
-import io.dropwizard.setup.Environment;
-
-/**
- * Production class for an application configuration of SelfService.
- */
-public class ProductionModule extends ModuleBase<ProvisioningServiceApplicationConfiguration> {
-
-	/**
-	 * Instantiates an application configuration of SelfService for production environment.
-	 *
-	 * @param configuration application configuration of SelfService.
-	 * @param environment   environment of SelfService.
-	 */
-	ProductionModule(ProvisioningServiceApplicationConfiguration configuration, Environment environment) {
-		super(configuration, environment);
-	}
-
-	@Override
-	protected void configure() {
-		bind(ProvisioningServiceApplicationConfiguration.class).toInstance(configuration);
-
-		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.SECURITY_SERVICE_NAME))
-				.toInstance(configuration.getSecurityFactory()
-						.build(environment, ServiceConsts.SECURITY_SERVICE_NAME, ServiceConsts
-								.PROVISIONING_USER_AGENT));
-
-		bind(RESTService.class).toInstance(configuration.getSelfFactory().build(environment, ServiceConsts
-				.SELF_SERVICE_NAME));
-		bind(MetadataHolder.class).to(DockerWarmuper.class);
-		bind(ICommandExecutor.class).to(CommandExecutor.class).asEagerSingleton();
-		bind(ObjectMapper.class).toInstance(new ObjectMapper().configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true));
-		bind(CallbackHandlerDao.class).to(FileSystemCallbackHandlerDao.class);
-		bind(RestoreCallbackHandlerService.class).to(RestoreCallbackHandlerServiceImpl.class);
-		bind(CheckInactivityService.class).to(CheckInactivityServiceImpl.class);
-		bind(ProjectService.class).to(ProjectServiceImpl.class);
-		if (configuration.getCloudProvider() == CloudProvider.GCP) {
-			bind(BucketService.class).to(BucketServiceGcpImpl.class);
-		} else if (configuration.getCloudProvider() == CloudProvider.AWS) {
-			bind(BucketService.class).to(BucketServiceAwsImpl.class);
-		} else if (configuration.getCloudProvider() == CloudProvider.AZURE) {
-			bind(BucketService.class).to(BucketServiceAzureImpl.class);
-		}
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java
deleted file mode 100644
index d4ec683..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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.modules;
-
-import com.epam.dlab.ModuleBase;
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.auth.contract.SecurityAPI;
-import com.epam.dlab.auth.dto.UserCredentialDTO;
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.DockerWarmuper;
-import com.epam.dlab.backendapi.core.MetadataHolder;
-import com.epam.dlab.backendapi.core.commands.CommandExecutorMock;
-import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
-import com.epam.dlab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
-import com.epam.dlab.backendapi.core.response.handlers.dao.FileSystemCallbackHandlerDao;
-import com.epam.dlab.backendapi.service.BucketService;
-import com.epam.dlab.backendapi.service.CheckInactivityService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.backendapi.service.RestoreCallbackHandlerService;
-import com.epam.dlab.backendapi.service.impl.CheckInactivityServiceImpl;
-import com.epam.dlab.backendapi.service.impl.ProjectServiceImpl;
-import com.epam.dlab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
-import com.epam.dlab.backendapi.service.impl.aws.BucketServiceAwsImpl;
-import com.epam.dlab.backendapi.service.impl.azure.BucketServiceAzureImpl;
-import com.epam.dlab.backendapi.service.impl.gcp.BucketServiceGcpImpl;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.DockerAPI;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.inject.name.Names;
-import io.dropwizard.setup.Environment;
-
-import javax.ws.rs.core.Response;
-
-/**
- * Mock class for an application configuration of Provisioning Service for tests.
- */
-public class ProvisioningDevModule extends ModuleBase<ProvisioningServiceApplicationConfiguration> implements
-		SecurityAPI, DockerAPI {
-
-	private static final String TOKEN = "token123";
-	private static final String OPERATION_IS_NOT_SUPPORTED = "Operation is not supported";
-
-	/**
-	 * Instantiates an application configuration of Provisioning Service for tests.
-	 *
-	 * @param configuration application configuration of Provisioning Service.
-	 * @param environment   environment of Provisioning Service.
-	 */
-	ProvisioningDevModule(ProvisioningServiceApplicationConfiguration configuration, Environment environment) {
-		super(configuration, environment);
-	}
-
-	@Override
-	protected void configure() {
-		bind(ProvisioningServiceApplicationConfiguration.class).toInstance(configuration);
-		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.SECURITY_SERVICE_NAME)).toInstance
-                (createAuthenticationService());
-        bind(RESTService.class).toInstance(configuration.getSelfFactory().build(environment, ServiceConsts
-                .SELF_SERVICE_NAME));
-        bind(MetadataHolder.class).to(DockerWarmuper.class);
-        bind(ICommandExecutor.class).toInstance(new CommandExecutorMock(configuration.getCloudProvider()));
-        bind(ObjectMapper.class).toInstance(new ObjectMapper().configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true));
-        bind(CallbackHandlerDao.class).to(FileSystemCallbackHandlerDao.class);
-        bind(RestoreCallbackHandlerService.class).to(RestoreCallbackHandlerServiceImpl.class);
-        bind(CheckInactivityService.class).to(CheckInactivityServiceImpl.class);
-        bind(ProjectService.class).to(ProjectServiceImpl.class);
-		if (configuration.getCloudProvider() == CloudProvider.GCP) {
-			bind(BucketService.class).to(BucketServiceGcpImpl.class);
-        } else if (configuration.getCloudProvider() == CloudProvider.AWS) {
-            bind(BucketService.class).to(BucketServiceAwsImpl.class);
-        } else if (configuration.getCloudProvider() == CloudProvider.AZURE) {
-            bind(BucketService.class).to(BucketServiceAzureImpl.class);
-        }
-    }
-
-	/**
-	 * Creates and returns the mock object for authentication service.
-	 */
-	@SuppressWarnings("unchecked")
-	private RESTService createAuthenticationService() {
-		return new RESTService() {
-			@Override
-			public <T> T post(String path, Object parameter, Class<T> clazz) {
-				if (LOGIN.equals(path)) {
-					return authorize((UserCredentialDTO) parameter);
-				} else if (GET_USER_INFO.equals(path) && TOKEN.equals(parameter) && clazz.equals(UserInfo.class)) {
-					return (T) getUserInfo();
-				}
-				throw new UnsupportedOperationException(OPERATION_IS_NOT_SUPPORTED);
-			}
-
-			private <T> T authorize(UserCredentialDTO credential) {
-				if ("test".equals(credential.getUsername())) {
-					return (T) Response.ok(TOKEN).build();
-				} else {
-					return (T) Response.status(Response.Status.UNAUTHORIZED)
-							.entity("Username or password is invalid")
-							.build();
-				}
-			}
-
-			@Override
-			public <T> T get(String path, Class<T> clazz) {
-				throw new UnsupportedOperationException(OPERATION_IS_NOT_SUPPORTED);
-			}
-
-			@Override
-			public <T> T get(String path, String accessToken, Class<T> clazz) {
-				throw new UnsupportedOperationException(OPERATION_IS_NOT_SUPPORTED);
-			}
-
-			@Override
-			public <T> T post(String path, String accessToken, Object parameter, Class<T> clazz) {
-				throw new UnsupportedOperationException(OPERATION_IS_NOT_SUPPORTED);
-			}
-		};
-	}
-
-	/**
-	 * Create and return UserInfo object.
-	 */
-	private UserInfo getUserInfo() {
-		UserInfo userInfo = new UserInfo("test", TOKEN);
-		userInfo.addRole("test");
-		userInfo.addRole("dev");
-		return userInfo;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/BackupResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/BackupResource.java
deleted file mode 100644
index 1263b20..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/BackupResource.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
-import com.epam.dlab.backendapi.core.commands.PythonBackupCommand;
-import com.epam.dlab.backendapi.core.response.folderlistener.FolderListenerExecutor;
-import com.epam.dlab.backendapi.core.response.handlers.BackupCallbackHandler;
-import com.epam.dlab.dto.backup.EnvBackupDTO;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.epam.dlab.rest.contracts.BackupAPI;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-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;
-
-@Path(BackupAPI.BACKUP)
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class BackupResource {
-
-	@Inject
-	private ProvisioningServiceApplicationConfiguration configuration;
-	@Inject
-	protected FolderListenerExecutor folderListenerExecutor;
-	@Inject
-	protected ICommandExecutor commandExecutor;
-	@Inject
-	protected RESTService selfService;
-
-
-	@POST
-	public Response createBackup(@Auth UserInfo ui, EnvBackupDTO dto) {
-		folderListenerExecutor.start(configuration.getBackupDirectory(), configuration.getProcessTimeout(),
-				new BackupCallbackHandler(selfService, ApiCallbacks.BACKUP_URI, ui.getName(), dto));
-		String command = new PythonBackupCommand(configuration.getBackupScriptPath())
-				.withConfig(dto.getConfigFiles())
-				.withJars(dto.getJars())
-				.withKeys(dto.getKeys())
-				.withDBBackup(dto.isDatabaseBackup())
-				.withLogsBackup(dto.isLogsBackup())
-				.withResponsePath(configuration.getBackupDirectory())
-				.withRequestId(dto.getId())
-				.withSystemUser()
-				.withCertificates(dto.getCertificates()).toCMD();
-		commandExecutor.executeAsync(ui.getName(), dto.getId(), command);
-		return Response.accepted(dto.getId()).build();
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/BucketResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/BucketResource.java
deleted file mode 100644
index bd21844..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/BucketResource.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.BucketService;
-import com.epam.dlab.dto.bucket.BucketDeleteDTO;
-import com.epam.dlab.dto.bucket.FolderUploadDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.fileupload.FileItemIterator;
-import org.apache.commons.fileupload.FileItemStream;
-import org.apache.commons.fileupload.servlet.ServletFileUpload;
-import org.apache.commons.fileupload.util.Streams;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-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.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.io.InputStream;
-
-@Slf4j
-@Path("/bucket")
-public class BucketResource {
-    private static final String OBJECT_FORM_FIELD = "object";
-    private static final String BUCKET_FORM_FIELD = "bucket";
-    private static final String SIZE_FORM_FIELD = "file-size";
-
-    private final BucketService bucketService;
-
-    @Inject
-    public BucketResource(BucketService bucketService) {
-        this.bucketService = bucketService;
-    }
-
-    @GET
-    @Path("/{bucket}")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    public Response getListOfObjects(@Auth UserInfo userInfo,
-                                     @PathParam("bucket") String bucket) {
-        return Response.ok(bucketService.getObjects(bucket)).build();
-    }
-
-    @POST
-    @Path("/upload")
-    @Consumes(MediaType.MULTIPART_FORM_DATA)
-    @Produces(MediaType.APPLICATION_JSON)
-    public Response uploadObject(@Auth UserInfo userInfo, @Context HttpServletRequest request) {
-        upload(request);
-        return Response.ok().build();
-    }
-
-    @POST
-    @Path("/folder/upload")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    public Response uploadFolder(@Auth UserInfo userInfo, @Valid FolderUploadDTO dto) {
-        bucketService.uploadFolder(userInfo, dto.getBucket(), dto.getFolder());
-        return Response.ok().build();
-    }
-
-    @GET
-    @Path("/{bucket}/object/{object}/download")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    public Response downloadObject(@Auth UserInfo userInfo, @Context HttpServletResponse resp,
-                                   @PathParam("object") String object,
-                                   @PathParam("bucket") String bucket) {
-        bucketService.downloadObject(bucket, object, resp);
-        return Response.ok().build();
-    }
-
-    @POST
-    @Path("/objects/delete")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    public Response uploadObject(@Auth UserInfo userInfo, BucketDeleteDTO bucketDeleteDTO) {
-        bucketService.deleteObjects(bucketDeleteDTO.getBucket(), bucketDeleteDTO.getObjects());
-        return Response.ok().build();
-    }
-
-    private void upload(HttpServletRequest request) {
-        String object = null;
-        String bucket = null;
-        long fileSize = 0;
-
-        ServletFileUpload upload = new ServletFileUpload();
-        try {
-            FileItemIterator iterStream = upload.getItemIterator(request);
-            while (iterStream.hasNext()) {
-                FileItemStream item = iterStream.next();
-                try (InputStream stream = item.openStream()) {
-                    if (item.isFormField()) {
-                        if (OBJECT_FORM_FIELD.equals(item.getFieldName())) {
-                            object = Streams.asString(stream);
-                        }
-                        if (BUCKET_FORM_FIELD.equals(item.getFieldName())) {
-                            bucket = Streams.asString(stream);
-                        }
-                        if (SIZE_FORM_FIELD.equals(item.getFieldName())) {
-                            fileSize = Long.parseLong(Streams.asString(stream));
-                        }
-                    } else {
-                        bucketService.uploadObject(bucket, object, stream, item.getContentType(), fileSize);
-                    }
-                } catch (Exception e) {
-                    log.error("Cannot upload object {} to bucket {}. {}", object, bucket, e.getMessage(), e);
-                    throw new DlabException(String.format("Cannot upload object %s to bucket %s. %s", object, bucket, e.getMessage()));
-                }
-            }
-        } catch (Exception e) {
-            log.error("Cannot upload object {} to bucket {}. {}", object, bucket, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot upload object %s to bucket %s. %s", object, bucket, e.getMessage()));
-        }
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/CallbackHandlerResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/CallbackHandlerResource.java
deleted file mode 100644
index 804b109..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/CallbackHandlerResource.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.backendapi.service.RestoreCallbackHandlerService;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.core.Response;
-
-@Path("/handler")
-@Slf4j
-public class CallbackHandlerResource {
-	private final RestoreCallbackHandlerService restoreCallbackHandlerService;
-
-	@Inject
-	public CallbackHandlerResource(RestoreCallbackHandlerService restoreCallbackHandlerService) {
-		this.restoreCallbackHandlerService = restoreCallbackHandlerService;
-	}
-
-	@POST
-	@Path("/restore")
-	public Response restoreHandlers() {
-		restoreCallbackHandlerService.restore();
-		return Response.ok().build();
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/DockerResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/DockerResource.java
deleted file mode 100644
index 5f6bbc6..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/DockerResource.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.core.MetadataHolder;
-import com.epam.dlab.backendapi.core.commands.CommandBuilder;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.dto.imagemetadata.ImageMetadataDTO;
-import com.epam.dlab.dto.imagemetadata.ImageType;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
-import java.util.Set;
-
-@Path("/docker")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class DockerResource implements DockerCommands {
-    private static final Logger LOGGER = LoggerFactory.getLogger(DockerResource.class);
-
-    @Inject
-    private ProvisioningServiceApplicationConfiguration configuration;
-    @Inject
-    private MetadataHolder metadataHolder;
-    @Inject
-    private ICommandExecutor commandExecutor;
-    @Inject
-    private CommandBuilder commandBuilder;
-
-    @GET
-    @Path("{type}")
-    public Set<ImageMetadataDTO> getDockerImages(@Auth UserInfo ui, @PathParam("type") String type) {
-        LOGGER.debug("docker statuses asked for {}", type);
-        return metadataHolder
-                .getMetadata(ImageType.valueOf(type.toUpperCase()));
-    }
-
-    @Path("/run")
-    @POST
-    public String run(@Auth UserInfo ui, String image) {
-        LOGGER.debug("run docker image {}", image);
-        String uuid = DockerCommands.generateUUID();
-        commandExecutor.executeAsync(
-                ui.getName(),
-                uuid,
-                new RunDockerCommand()
-                        .withName(nameContainer("image", "runner"))
-                        .withVolumeForRootKeys(configuration.getKeyDirectory())
-                        .withVolumeForResponse(configuration.getImagesDirectory())
-                        .withRequestId(uuid)
-                        .withDryRun()
-                        .withActionRun(image)
-                        .toCMD()
-        );
-        return uuid;
-    }
-
-    public String getResourceType() {
-        return Directories.NOTEBOOK_LOG_DIRECTORY;
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/GitExploratoryResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/GitExploratoryResource.java
deleted file mode 100644
index e6f6476..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/GitExploratoryResource.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.handlers.ExploratoryGitCredsCallbackHandler;
-import com.epam.dlab.backendapi.service.impl.DockerService;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.exploratory.ExploratoryBaseDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.util.Objects;
-
-@Path("/exploratory")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class GitExploratoryResource extends DockerService implements DockerCommands {
-
-	@Path("/git_creds")
-	@POST
-	public String gitCredsUpdate(@Auth UserInfo ui, ExploratoryGitCredsUpdateDTO dto) throws JsonProcessingException {
-		return action(ui.getName(), dto, DockerAction.GIT_CREDS);
-	}
-
-	private String action(String username, ExploratoryBaseDTO<?> dto, DockerAction action) throws JsonProcessingException {
-		log.debug("{} exploratory environment", action);
-		String uuid = DockerCommands.generateUUID();
-		folderListenerExecutor.start(configuration.getImagesDirectory(),
-				configuration.getResourceStatusPollTimeout(),
-				getFileHandlerCallback(action, uuid, dto));
-
-		RunDockerCommand runDockerCommand = new RunDockerCommand()
-				.withInteractive()
-				.withName(nameContainer(dto.getEdgeUserName(), action, dto.getExploratoryName()))
-				.withVolumeForRootKeys(configuration.getKeyDirectory())
-				.withVolumeForResponse(configuration.getImagesDirectory())
-				.withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
-				.withResource(getResourceType())
-				.withRequestId(uuid)
-				.withConfKeyName(configuration.getAdminKey())
-				.withImage(dto.getNotebookImage())
-				.withAction(action);
-		if (configuration.getCloudProvider() == CloudProvider.AZURE &&
-				Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
-				!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
-			runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
-		}
-
-		commandExecutor.executeAsync(username, uuid, commandBuilder.buildCommand(runDockerCommand, dto));
-		return uuid;
-	}
-
-	private FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, ExploratoryBaseDTO<?> dto) {
-		return new ExploratoryGitCredsCallbackHandler(selfService, action, uuid, dto.getCloudSettings().getIamUser(), dto.getExploratoryName());
-	}
-
-	private String nameContainer(String user, DockerAction action, String name) {
-		return nameContainer(user, action.toString(), "exploratory", name);
-	}
-
-	public String getResourceType() {
-		return Directories.NOTEBOOK_LOG_DIRECTORY;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ImageResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ImageResource.java
deleted file mode 100644
index 2d6d9e3..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ImageResource.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.handlers.ImageCreateCallbackHandler;
-import com.epam.dlab.backendapi.service.impl.DockerService;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.exploratory.ExploratoryImageDTO;
-import com.epam.dlab.rest.contracts.ExploratoryAPI;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-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;
-import java.util.Objects;
-
-@Path(ExploratoryAPI.EXPLORATORY_IMAGE)
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ImageResource extends DockerService implements DockerCommands {
-
-	@POST
-	public Response createImage(@Auth UserInfo ui, ExploratoryImageDTO image) throws JsonProcessingException {
-		final String uuid = DockerCommands.generateUUID();
-
-		folderListenerExecutor.start(configuration.getImagesDirectory(), configuration.getResourceStatusPollTimeout(),
-				new ImageCreateCallbackHandler(selfService, uuid, DockerAction.CREATE_IMAGE, image));
-		String command = commandBuilder.buildCommand(getDockerCommand(DockerAction.CREATE_IMAGE, uuid, image), image);
-		commandExecutor.executeAsync(ui.getName(), uuid, command);
-		log.debug("Docker command: " + command);
-		return Response.accepted(uuid).build();
-	}
-
-
-	@Override
-	public String getResourceType() {
-		return Directories.NOTEBOOK_LOG_DIRECTORY;
-	}
-
-	private RunDockerCommand getDockerCommand(DockerAction action, String uuid, ExploratoryImageDTO image) {
-		RunDockerCommand runDockerCommand = new RunDockerCommand()
-				.withInteractive()
-				.withVolumeForRootKeys(configuration.getKeyDirectory())
-				.withVolumeForResponse(configuration.getImagesDirectory())
-				.withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
-				.withRequestId(uuid)
-				.withConfKeyName(configuration.getAdminKey())
-				.withAction(action)
-				.withResource(getResourceType())
-				.withImage(image.getNotebookImage())
-				.withName(nameContainer(image.getEdgeUserName(), action.toString(), image.getImageName()));
-		if (configuration.getCloudProvider() == CloudProvider.AZURE &&
-				Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
-				!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
-			runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
-		}
-
-		return runDockerCommand;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureResource.java
deleted file mode 100644
index 91519ab..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureResource.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.CheckInactivityService;
-import com.epam.dlab.dto.computational.ComputationalCheckInactivityDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryCheckInactivityAction;
-import com.epam.dlab.rest.contracts.InfrasctructureAPI;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-@Path(InfrasctructureAPI.INFRASTRUCTURE)
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class InfrastructureResource {
-
-	@Inject
-	private CheckInactivityService checkInactivityService;
-
-	/**
-	 * Return status of provisioning service.
-	 */
-	@GET
-	public Response status(@Auth UserInfo ui) {
-		return Response.status(Response.Status.OK).build();
-	}
-
-	@POST
-	@Path("/exploratory/check_inactivity")
-	public String checkExploratoryInactivity(@Auth UserInfo ui, ExploratoryCheckInactivityAction dto) {
-		return checkInactivityService.checkExploratoryInactivity(ui.getName(), dto);
-	}
-
-	@POST
-	@Path("/computational/check_inactivity")
-	public String checkComputationalInactivity(@Auth UserInfo ui, ComputationalCheckInactivityDTO dto) {
-		return checkInactivityService.checkComputationalInactivity(ui.getName(), dto);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/LibraryResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/LibraryResource.java
deleted file mode 100644
index dafa72e..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/LibraryResource.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.handlers.LibInstallCallbackHandler;
-import com.epam.dlab.backendapi.core.response.handlers.LibListCallbackHandler;
-import com.epam.dlab.backendapi.service.impl.DockerService;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.LibListComputationalDTO;
-import com.epam.dlab.dto.LibListExploratoryDTO;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.exploratory.ExploratoryActionDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryBaseDTO;
-import com.epam.dlab.dto.exploratory.LibraryInstallDTO;
-import com.epam.dlab.rest.contracts.ComputationalAPI;
-import com.epam.dlab.rest.contracts.ExploratoryAPI;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.util.Objects;
-
-@Path("/library")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class LibraryResource extends DockerService implements DockerCommands {
-
-
-	@POST
-	@Path(ExploratoryAPI.EXPLORATORY + "/lib_list")
-	public String getLibList(@Auth UserInfo ui, LibListExploratoryDTO dto) throws JsonProcessingException {
-		return actionExploratory(ui.getName(), dto, DockerAction.LIB_LIST);
-	}
-
-	@POST
-	@Path(ExploratoryAPI.EXPLORATORY + "/lib_install")
-	public String libInstall(@Auth UserInfo ui, LibraryInstallDTO dto) throws JsonProcessingException {
-		return actionExploratory(ui.getName(), dto, DockerAction.LIB_INSTALL);
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL + "/lib_list")
-	public String getLibList(@Auth UserInfo ui, LibListComputationalDTO dto) throws JsonProcessingException {
-		return actionComputational(ui.getName(), dto, DockerAction.LIB_LIST);
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL + "/lib_install")
-	public String getLibList(@Auth UserInfo ui, LibraryInstallDTO dto) throws JsonProcessingException {
-		return actionComputational(ui.getName(), dto, DockerAction.LIB_INSTALL);
-	}
-
-	private String actionExploratory(String username, ExploratoryBaseDTO<?> dto, DockerAction action) throws JsonProcessingException {
-		log.debug("{} user {} exploratory environment {}", action, username, dto);
-		String uuid = DockerCommands.generateUUID();
-		folderListenerExecutor.start(configuration.getImagesDirectory(),
-				configuration.getResourceStatusPollTimeout(),
-				getFileHandlerCallbackExploratory(action, uuid, dto));
-
-		RunDockerCommand runDockerCommand = getDockerCommandExploratory(dto, action, uuid);
-
-		commandExecutor.executeAsync(username, uuid, commandBuilder.buildCommand(runDockerCommand, dto));
-		return uuid;
-	}
-
-	private String actionComputational(String username, ExploratoryActionDTO<?> dto, DockerAction action) throws JsonProcessingException {
-		log.debug("{} user {} exploratory environment {}", action, username, dto);
-		String uuid = DockerCommands.generateUUID();
-		folderListenerExecutor.start(configuration.getImagesDirectory(),
-				configuration.getResourceStatusPollTimeout(),
-				getFileHandlerCallbackComputational(action, uuid, dto));
-
-		RunDockerCommand runDockerCommand = getDockerCommandComputational(dto, action, uuid);
-
-		commandExecutor.executeAsync(username, uuid, commandBuilder.buildCommand(runDockerCommand, dto));
-		return uuid;
-	}
-
-	private RunDockerCommand getDockerCommandExploratory(ExploratoryBaseDTO<?> dto, DockerAction action, String uuid) {
-		return getDockerCommand(action, uuid)
-				.withName(nameContainer(dto.getEdgeUserName(), action.toString(), "exploratory",
-						dto.getExploratoryName()))
-				.withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
-				.withResource(getResourceType())
-				.withImage(dto.getNotebookImage());
-	}
-
-	private RunDockerCommand getDockerCommandComputational(ExploratoryActionDTO<?> dto, DockerAction action,
-														   String uuid) {
-		RunDockerCommand runDockerCommand = getDockerCommand(action, uuid);
-		if (dto instanceof LibraryInstallDTO) {
-			LibraryInstallDTO newDTO = (LibraryInstallDTO) dto;
-			runDockerCommand.withName(nameContainer(dto.getEdgeUserName(), action.toString(),
-					"computational", newDTO.getComputationalId()))
-					.withVolumeForLog(configuration.getDockerLogDirectory(),
-							DataEngineType.fromDockerImageName(newDTO.getComputationalImage()).getName())
-					.withResource(DataEngineType.fromDockerImageName(newDTO.getComputationalImage()).getName())
-
-					.withImage(newDTO.getComputationalImage());
-
-		} else {
-			LibListComputationalDTO newDTO = (LibListComputationalDTO) dto;
-
-			runDockerCommand.withName(nameContainer(dto.getEdgeUserName(), action.toString(),
-					"computational", newDTO.getComputationalId()))
-					.withVolumeForLog(configuration.getDockerLogDirectory(),
-							DataEngineType.fromDockerImageName(newDTO.getComputationalImage()).getName())
-					.withResource(DataEngineType.fromDockerImageName(newDTO.getComputationalImage()).getName())
-					.withImage(newDTO.getComputationalImage());
-
-		}
-		return runDockerCommand;
-	}
-
-	private RunDockerCommand getDockerCommand(DockerAction action, String uuid) {
-		RunDockerCommand runDockerCommand = new RunDockerCommand()
-				.withInteractive()
-				.withVolumeForRootKeys(configuration.getKeyDirectory())
-				.withVolumeForResponse(configuration.getImagesDirectory())
-				.withRequestId(uuid)
-				.withConfKeyName(configuration.getAdminKey())
-				.withAction(action);
-		if (configuration.getCloudProvider() == CloudProvider.AZURE &&
-				Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
-				!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
-			runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
-		}
-
-		return runDockerCommand;
-	}
-
-	private FileHandlerCallback getFileHandlerCallbackExploratory(DockerAction action, String uuid,
-																  ExploratoryBaseDTO<?> dto) {
-		switch (action) {
-			case LIB_LIST:
-				final String group = ((LibListExploratoryDTO) dto).getLibCacheKey();
-				return new LibListCallbackHandler(selfService, DockerAction.LIB_LIST, uuid,
-						dto.getCloudSettings().getIamUser(), group);
-			case LIB_INSTALL:
-				return new LibInstallCallbackHandler(selfService, action, uuid,
-						dto.getCloudSettings().getIamUser(),
-						(LibraryInstallDTO) dto);
-			default:
-				throw new IllegalArgumentException("Unknown action " + action);
-		}
-	}
-
-	private FileHandlerCallback getFileHandlerCallbackComputational(DockerAction action, String uuid,
-																	ExploratoryBaseDTO<?> dto) {
-		switch (action) {
-			case LIB_LIST:
-				return new LibListCallbackHandler(selfService, action, uuid,
-						dto.getCloudSettings().getIamUser(), ((LibListComputationalDTO) dto).getLibCacheKey());
-			case LIB_INSTALL:
-				return new LibInstallCallbackHandler(selfService, action, uuid,
-						dto.getCloudSettings().getIamUser(), ((LibraryInstallDTO) dto));
-
-			default:
-				throw new IllegalArgumentException("Unknown action " + action);
-		}
-	}
-
-	public String getResourceType() {
-		return Directories.NOTEBOOK_LOG_DIRECTORY;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
deleted file mode 100644
index 2113e8c..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.dto.project.ProjectActionDTO;
-import com.epam.dlab.dto.project.ProjectCreateDTO;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-
-import javax.ws.rs.Consumes;
-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;
-
-@Path("infrastructure/project")
-public class ProjectResource {
-	private final ProjectService projectService;
-
-	@Inject
-	public ProjectResource(ProjectService projectService) {
-		this.projectService = projectService;
-	}
-
-	@Path("/create")
-	@POST
-	@Consumes(MediaType.APPLICATION_JSON)
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response createProject(@Auth UserInfo userInfo, ProjectCreateDTO dto) {
-		return Response.ok(projectService.create(userInfo, dto)).build();
-	}
-
-	@Path("/terminate")
-	@POST
-	@Consumes(MediaType.APPLICATION_JSON)
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response terminateProject(@Auth UserInfo userInfo, ProjectActionDTO dto) {
-		return Response.ok(projectService.terminate(userInfo, dto)).build();
-	}
-
-	@Path("/start")
-	@POST
-	@Consumes(MediaType.APPLICATION_JSON)
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response startProject(@Auth UserInfo userInfo, ProjectActionDTO dto) {
-		return Response.ok(projectService.start(userInfo, dto)).build();
-	}
-
-	@Path("/stop")
-	@POST
-	@Consumes(MediaType.APPLICATION_JSON)
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response stopProject(@Auth UserInfo userInfo, ProjectActionDTO dto) {
-		return Response.ok(projectService.stop(userInfo, dto)).build();
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ProvisioningHealthCheckResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ProvisioningHealthCheckResource.java
deleted file mode 100644
index a46171b..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ProvisioningHealthCheckResource.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.resources;
-
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-@Path("/healthcheck")
-@Produces(MediaType.APPLICATION_JSON)
-public class ProvisioningHealthCheckResource {
-    @Inject
-    private ProvisioningServiceApplicationConfiguration configuration;
-
-    @GET
-    public Response status(@Auth UserInfo ui) {
-        return Response.ok(configuration.getCloudProvider()).build();
-    }
-}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ComputationalResourceAws.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ComputationalResourceAws.java
deleted file mode 100644
index 8e8730c..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ComputationalResourceAws.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * 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.resources.aws;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.handlers.ComputationalCallbackHandler;
-import com.epam.dlab.backendapi.core.response.handlers.ComputationalConfigure;
-import com.epam.dlab.backendapi.service.impl.DockerService;
-import com.epam.dlab.backendapi.service.impl.SparkClusterService;
-import com.epam.dlab.dto.aws.computational.AwsComputationalTerminateDTO;
-import com.epam.dlab.dto.aws.computational.ComputationalCreateAws;
-import com.epam.dlab.dto.aws.computational.SparkComputationalCreateAws;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.epam.dlab.dto.computational.ComputationalClusterConfigDTO;
-import com.epam.dlab.dto.computational.ComputationalStartDTO;
-import com.epam.dlab.dto.computational.ComputationalStopDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.contracts.ComputationalAPI;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-import static com.epam.dlab.backendapi.core.commands.DockerAction.CREATE;
-import static com.epam.dlab.backendapi.core.commands.DockerAction.TERMINATE;
-
-@Path("/")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ComputationalResourceAws extends DockerService implements DockerCommands {
-
-	private static final DataEngineType EMR_DATA_ENGINE = DataEngineType.CLOUD_SERVICE;
-	@Inject
-	private ComputationalConfigure computationalConfigure;
-	@Inject
-	private SparkClusterService sparkClusterService;
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_CREATE_CLOUD_SPECIFIC)
-	public String create(@Auth UserInfo ui, ComputationalCreateAws dto) {
-		log.debug("Create computational resources {} for user {}: {}", dto.getComputationalName(), ui.getName(), dto);
-		String uuid = DockerCommands.generateUUID();
-		folderListenerExecutor.start(configuration.getImagesDirectory(),
-				configuration.getResourceStatusPollTimeout(),
-				getFileHandlerCallback(CREATE, uuid, dto));
-		try {
-			long timeout = configuration.getResourceStatusPollTimeout().toSeconds();
-			commandExecutor.executeAsync(
-					ui.getName(),
-					uuid,
-					commandBuilder.buildCommand(
-							new RunDockerCommand()
-									.withInteractive()
-									.withName(nameContainer(dto.getEdgeUserName(), CREATE, dto.getExploratoryName(),
-											dto.getComputationalName()))
-									.withVolumeForRootKeys(configuration.getKeyDirectory())
-									.withVolumeForResponse(configuration.getImagesDirectory())
-									.withVolumeForLog(configuration.getDockerLogDirectory(), EMR_DATA_ENGINE.getName())
-									.withResource(EMR_DATA_ENGINE.getName())
-									.withRequestId(uuid)
-									.withEc2Role(configuration.getEmrEC2RoleDefault())
-									.withEmrTimeout(Long.toString(timeout))
-									.withServiceRole(configuration.getEmrServiceRoleDefault())
-									.withConfKeyName(configuration.getAdminKey())
-									.withActionCreate(DataEngineType.getDockerImageName(EMR_DATA_ENGINE)),
-							dto
-					)
-			);
-		} catch (Exception t) {
-			throw new DlabException("Could not create computational resource cluster", t);
-		}
-		return uuid;
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC)
-	public String terminate(@Auth UserInfo ui, AwsComputationalTerminateDTO dto) {
-
-		log.debug("Terminate computational resources {} for user {}: {}", dto.getComputationalName(), ui.getName(),
-				dto);
-		String uuid = DockerCommands.generateUUID();
-		folderListenerExecutor.start(configuration.getImagesDirectory(),
-				configuration.getResourceStatusPollTimeout(),
-				getFileHandlerCallback(TERMINATE, uuid, dto));
-		try {
-			commandExecutor.executeAsync(
-					ui.getName(),
-					uuid,
-					commandBuilder.buildCommand(
-							new RunDockerCommand()
-									.withInteractive()
-									.withName(nameContainer(dto.getEdgeUserName(), TERMINATE,
-											dto.getExploratoryName(), dto.getComputationalName()))
-									.withVolumeForRootKeys(configuration.getKeyDirectory())
-									.withVolumeForResponse(configuration.getImagesDirectory())
-									.withVolumeForLog(configuration.getDockerLogDirectory(), EMR_DATA_ENGINE.getName())
-									.withResource(EMR_DATA_ENGINE.getName())
-									.withRequestId(uuid)
-									.withConfKeyName(configuration.getAdminKey())
-									.withActionTerminate(DataEngineType.getDockerImageName(EMR_DATA_ENGINE)),
-							dto
-					)
-			);
-		} catch (JsonProcessingException t) {
-			throw new DlabException("Could not terminate computational resources cluster", t);
-		}
-
-		return uuid;
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_CREATE_SPARK)
-	public String createSparkCluster(@Auth UserInfo ui, SparkComputationalCreateAws dto) {
-		log.debug("Create computational Spark resources {} for user {}: {}", dto.getComputationalName(), ui.getName(),
-				dto);
-
-		return sparkClusterService.create(ui, dto);
-	}
-
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_TERMINATE_SPARK)
-	public String terminateSparkCluster(@Auth UserInfo ui, AwsComputationalTerminateDTO dto) {
-		log.debug("Terminate computational Spark resource {} for user {}: {}", dto.getComputationalName(), ui.getName
-				(), dto);
-
-		return sparkClusterService.terminate(ui, dto);
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_STOP_SPARK)
-	public String stopSparkCluster(@Auth UserInfo ui, ComputationalStopDTO dto) {
-		log.debug("Stop computational Spark resources {} for user {}: {}",
-				dto.getComputationalName(), ui.getName(), dto);
-
-		return sparkClusterService.stop(ui, dto);
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_START_SPARK)
-	public String startSparkCluster(@Auth UserInfo ui, ComputationalStartDTO dto) {
-		log.debug("Start computational Spark resource {} for user {}: {}",
-				dto.getComputationalName(), ui.getName(), dto);
-
-		return sparkClusterService.start(ui, dto);
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_RECONFIGURE_SPARK)
-	public String reconfigureSparkCluster(@Auth UserInfo ui, ComputationalClusterConfigDTO config) {
-		log.debug("User is reconfiguring {} spark cluster for exploratory {}", ui.getName(),
-				config.getComputationalName(), config.getNotebookInstanceName());
-		return sparkClusterService.updateConfig(ui, config);
-	}
-
-	private FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, ComputationalBase<?> dto) {
-		return new ComputationalCallbackHandler(computationalConfigure, selfService, action, uuid, dto);
-	}
-
-	private String nameContainer(String user, DockerAction action, String exploratoryName, String name) {
-		return nameContainer(user, action.toString(), "computational", exploratoryName, name);
-	}
-
-	public String getResourceType() {
-		return Directories.DATA_ENGINE_SERVICE_LOG_DIRECTORY;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/aws/EdgeResourceAws.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/aws/EdgeResourceAws.java
deleted file mode 100644
index 57956f3..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/aws/EdgeResourceAws.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.resources.aws;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.response.handlers.EdgeCallbackHandler;
-import com.epam.dlab.backendapi.resources.base.EdgeService;
-import com.epam.dlab.dto.ResourceSysBaseDTO;
-import com.epam.dlab.dto.aws.edge.EdgeInfoAws;
-import com.epam.dlab.dto.aws.keyload.UploadFileAws;
-import com.epam.dlab.dto.base.keyload.UploadFileResult;
-import com.epam.dlab.util.FileUtils;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.io.IOException;
-
-import static com.epam.dlab.rest.contracts.ApiCallbacks.EDGE;
-import static com.epam.dlab.rest.contracts.ApiCallbacks.KEY_LOADER;
-import static com.epam.dlab.rest.contracts.ApiCallbacks.STATUS_URI;
-
-/**
- * Provides API to manage Edge node on AWS
- */
-@Path("infrastructure/edge")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class EdgeResourceAws extends EdgeService {
-
-	public EdgeResourceAws() {
-		log.info("{} is initialized", getClass().getSimpleName());
-	}
-
-	@POST
-	@Path("/create")
-	public String create(@Auth UserInfo ui, UploadFileAws dto) throws IOException {
-		FileUtils.saveToFile(getKeyFilename(dto.getEdge().getEdgeUserName()), getKeyDirectory(), dto.getContent());
-		return action(ui.getName(), dto.getEdge(), dto.getEdge().getCloudSettings().getIamUser(), KEY_LOADER,
-				DockerAction.CREATE);
-	}
-
-	@POST
-	@Path("/start")
-	public String start(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
-		return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI, DockerAction.START);
-	}
-
-	@POST
-	@Path("/stop")
-	public String stop(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
-		return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI, DockerAction.STOP);
-	}
-
-	@POST
-	@Path("/terminate")
-	public String terminate(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
-		return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI,
-				DockerAction.TERMINATE);
-	}
-
-	@SuppressWarnings("unchecked")
-	protected FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, String user, String
-			callbackURI) {
-		return new EdgeCallbackHandler(selfService, action, uuid, user, callbackURI,
-				EdgeInfoAws.class,
-				UploadFileResult.class);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ExploratoryResourceAws.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ExploratoryResourceAws.java
deleted file mode 100644
index 9f7dfc5..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ExploratoryResourceAws.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.resources.aws;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.resources.base.ExploratoryService;
-import com.epam.dlab.dto.aws.exploratory.ExploratoryCreateAws;
-import com.epam.dlab.dto.exploratory.ExploratoryActionDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-@Path("/exploratory")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class ExploratoryResourceAws {
-
-	@Inject
-	private ExploratoryService exploratoryService;
-
-
-	@Path("/create")
-	@POST
-	public String create(@Auth UserInfo ui, ExploratoryCreateAws dto) throws JsonProcessingException {
-		return exploratoryService.action(ui.getName(), dto, DockerAction.CREATE);
-	}
-
-	@Path("/start")
-	@POST
-	public String start(@Auth UserInfo ui, ExploratoryGitCredsUpdateDTO dto) throws JsonProcessingException {
-		return exploratoryService.action(ui.getName(), dto, DockerAction.START);
-	}
-
-	@Path("/terminate")
-	@POST
-	public String terminate(@Auth UserInfo ui, ExploratoryActionDTO<?> dto) throws JsonProcessingException {
-		return exploratoryService.action(ui.getName(), dto, DockerAction.TERMINATE);
-	}
-
-	@Path("/stop")
-	@POST
-	public String stop(@Auth UserInfo ui, ExploratoryActionDTO<?> dto) throws JsonProcessingException {
-		return exploratoryService.action(ui.getName(), dto, DockerAction.STOP);
-	}
-
-	@Path("/reconfigure_spark")
-	@POST
-	public String reconfigureSpark(@Auth UserInfo ui, ExploratoryReconfigureSparkClusterActionDTO dto) throws JsonProcessingException {
-		return exploratoryService.action(ui.getName(), dto, DockerAction.RECONFIGURE_SPARK);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/aws/InfrastructureResourceAws.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/aws/InfrastructureResourceAws.java
deleted file mode 100644
index 6efc41f..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/aws/InfrastructureResourceAws.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.resources.aws;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.resources.base.InfrastructureService;
-import com.epam.dlab.dto.UserEnvironmentResources;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-@Path("/infrastructure")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class InfrastructureResourceAws extends InfrastructureService {
-    public InfrastructureResourceAws() {
-        log.info("{} is initialized", getClass().getSimpleName());
-    }
-
-    @Path("/status")
-    @POST
-    public String status(@Auth UserInfo ui, UserEnvironmentResources dto) {
-        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), DockerAction.STATUS);
-    }
-}
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
deleted file mode 100644
index 2ca5c42..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.resources.azure;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.impl.SparkClusterService;
-import com.epam.dlab.dto.azure.computational.SparkComputationalCreateAzure;
-import com.epam.dlab.dto.computational.ComputationalClusterConfigDTO;
-import com.epam.dlab.dto.computational.ComputationalStartDTO;
-import com.epam.dlab.dto.computational.ComputationalStopDTO;
-import com.epam.dlab.dto.computational.ComputationalTerminateDTO;
-import com.epam.dlab.rest.contracts.ComputationalAPI;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-@Path("/")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ComputationalResourceAzure implements ComputationalAPI {
-
-	@Inject
-	private SparkClusterService sparkClusterService;
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_CREATE_SPARK)
-	public String create(@Auth UserInfo ui, SparkComputationalCreateAzure dto) {
-		log.debug("Create computational Spark resources {} for user {}: {}",
-				dto.getComputationalName(), ui.getName(), dto);
-
-		return sparkClusterService.create(ui, dto);
-	}
-
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_TERMINATE_SPARK)
-	public String terminate(@Auth UserInfo ui, ComputationalTerminateDTO dto) {
-		log.debug("Terminate computational Spark resources {} for user {}: {}",
-				dto.getComputationalName(), ui.getName(), dto);
-
-		return sparkClusterService.terminate(ui, dto);
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_STOP_SPARK)
-	public String stopSparkCluster(@Auth UserInfo ui, ComputationalStopDTO dto) {
-		log.debug("Stop computational Spark resources {} for user {}: {}",
-				dto.getComputationalName(), ui.getName(), dto);
-
-		return sparkClusterService.stop(ui, dto);
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_START_SPARK)
-	public String startSparkCluster(@Auth UserInfo ui, ComputationalStartDTO dto) {
-		log.debug("Start computational Spark resource {} for user {}: {}",
-				dto.getComputationalName(), ui.getName(), dto);
-
-		return sparkClusterService.start(ui, dto);
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_RECONFIGURE_SPARK)
-	public String reconfigureSparkCluster(@Auth UserInfo ui, ComputationalClusterConfigDTO config) {
-		log.debug("User is reconfiguring {} spark cluster for exploratory {}", ui.getName(),
-				config.getComputationalName(), config.getNotebookInstanceName());
-		return sparkClusterService.updateConfig(ui, config);
-	}
-
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/EdgeResourceAzure.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/EdgeResourceAzure.java
deleted file mode 100644
index 7781227..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/EdgeResourceAzure.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.resources.azure;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.response.handlers.EdgeCallbackHandler;
-import com.epam.dlab.backendapi.resources.base.EdgeService;
-import com.epam.dlab.dto.ResourceSysBaseDTO;
-import com.epam.dlab.dto.azure.edge.EdgeInfoAzure;
-import com.epam.dlab.dto.azure.keyload.UploadFileAzure;
-import com.epam.dlab.dto.base.keyload.UploadFileResult;
-import com.epam.dlab.util.FileUtils;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.io.IOException;
-
-import static com.epam.dlab.rest.contracts.ApiCallbacks.EDGE;
-import static com.epam.dlab.rest.contracts.ApiCallbacks.KEY_LOADER;
-import static com.epam.dlab.rest.contracts.ApiCallbacks.STATUS_URI;
-
-/**
- * Provides API to manage Edge node on Azure
- */
-@Path("infrastructure/edge")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class EdgeResourceAzure extends EdgeService {
-
-	public EdgeResourceAzure() {
-		log.info("{} is initialized", getClass().getSimpleName());
-	}
-
-	@POST
-	@Path("/create")
-	public String create(@Auth UserInfo ui, UploadFileAzure dto) throws IOException {
-		FileUtils.saveToFile(getKeyFilename(dto.getEdge().getEdgeUserName()), getKeyDirectory(), dto.getContent());
-		return action(ui.getName(), dto.getEdge(), dto.getEdge().getCloudSettings().getIamUser(), KEY_LOADER,
-				DockerAction.CREATE);
-	}
-
-	@POST
-	@Path("/start")
-	public String start(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
-		return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI, DockerAction.START);
-	}
-
-	@POST
-	@Path("/stop")
-	public String stop(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
-		return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI, DockerAction.STOP);
-	}
-
-	@POST
-	@Path("/terminate")
-	public String terminate(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
-		return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI,
-				DockerAction.TERMINATE);
-	}
-
-	@SuppressWarnings("unchecked")
-	protected FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, String user, String
-			callbackURI) {
-		return new EdgeCallbackHandler(selfService, action, uuid, user, callbackURI,
-				EdgeInfoAzure.class,
-				UploadFileResult.class);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ExploratoryResourceAzure.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ExploratoryResourceAzure.java
deleted file mode 100644
index 3fa4f6f..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ExploratoryResourceAzure.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.resources.azure;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.resources.base.ExploratoryService;
-import com.epam.dlab.dto.azure.exploratory.ExploratoryActionStartAzure;
-import com.epam.dlab.dto.azure.exploratory.ExploratoryActionStopAzure;
-import com.epam.dlab.dto.azure.exploratory.ExploratoryCreateAzure;
-import com.epam.dlab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-@Path("/exploratory")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class ExploratoryResourceAzure {
-    @Inject
-    private ExploratoryService exploratoryService;
-
-    @Path("/create")
-    @POST
-    public String create(@Auth UserInfo ui, ExploratoryCreateAzure dto) throws JsonProcessingException {
-        return exploratoryService.action(ui.getName(), dto, DockerAction.CREATE);
-    }
-
-    @Path("/start")
-    @POST
-    public String start(@Auth UserInfo ui, ExploratoryActionStartAzure dto) throws JsonProcessingException {
-        return exploratoryService.action(ui.getName(), dto, DockerAction.START);
-    }
-
-    @Path("/terminate")
-    @POST
-    public String terminate(@Auth UserInfo ui, ExploratoryActionStopAzure dto) throws JsonProcessingException {
-        return exploratoryService.action(ui.getName(), dto, DockerAction.TERMINATE);
-    }
-
-    @Path("/stop")
-    @POST
-    public String stop(@Auth UserInfo ui, ExploratoryActionStopAzure dto) throws JsonProcessingException {
-        return exploratoryService.action(ui.getName(), dto, DockerAction.STOP);
-    }
-
-    @Path("/reconfigure_spark")
-    @POST
-    public String reconfigureSpark(@Auth UserInfo ui, ExploratoryReconfigureSparkClusterActionDTO dto) throws JsonProcessingException {
-        return exploratoryService.action(ui.getName(), dto, DockerAction.RECONFIGURE_SPARK);
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/InfrastructureResourceAzure.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/InfrastructureResourceAzure.java
deleted file mode 100644
index 0915c30..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/InfrastructureResourceAzure.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.resources.azure;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.resources.base.InfrastructureService;
-import com.epam.dlab.dto.UserEnvironmentResources;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-@Path("/infrastructure")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class InfrastructureResourceAzure extends InfrastructureService {
-
-    public InfrastructureResourceAzure() {
-        log.info("{} is initialized", getClass().getSimpleName());
-    }
-
-    @Path("/status")
-    @POST
-    public String status(@Auth UserInfo ui, UserEnvironmentResources dto) {
-        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), DockerAction.STATUS);
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/base/EdgeService.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/base/EdgeService.java
deleted file mode 100644
index 92cb6e8..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/base/EdgeService.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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.resources.base;
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.*;
-import com.epam.dlab.backendapi.core.response.folderlistener.FolderListenerExecutor;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.ResourceSysBaseDTO;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.KeyAPI;
-import com.epam.dlab.util.UsernameUtils;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.inject.Inject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Objects;
-
-public abstract class EdgeService implements DockerCommands {
-
-	private final Logger logger = LoggerFactory.getLogger(getClass());
-
-	@Inject
-	protected RESTService selfService;
-	@Inject
-	private ProvisioningServiceApplicationConfiguration configuration;
-	@Inject
-	private FolderListenerExecutor folderListenerExecutor;
-	@Inject
-	private ICommandExecutor commandExecutor;
-	@Inject
-	private CommandBuilder commandBuilder;
-
-	@Override
-	public String getResourceType() {
-		return Directories.EDGE_LOG_DIRECTORY;
-	}
-
-	protected String action(String username, ResourceSysBaseDTO<?> dto, String iamUser, String callbackURI,
-							DockerAction action) throws JsonProcessingException {
-		logger.debug("{} EDGE node for user {}: {}", action, username, dto);
-		String uuid = DockerCommands.generateUUID();
-
-		folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
-				configuration.getKeyLoaderPollTimeout(),
-				getFileHandlerCallback(action, uuid, iamUser, callbackURI));
-
-		RunDockerCommand runDockerCommand = new RunDockerCommand()
-				.withInteractive()
-				.withName(nameContainer(dto.getEdgeUserName(), action))
-				.withVolumeForRootKeys(getKeyDirectory())
-				.withVolumeForResponse(configuration.getKeyLoaderDirectory())
-				.withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
-				.withResource(getResourceType())
-				.withRequestId(uuid)
-				.withConfKeyName(configuration.getAdminKey())
-				.withImage(configuration.getEdgeImage())
-				.withAction(action);
-		if (configuration.getCloudProvider() == CloudProvider.AZURE &&
-				Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
-				!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
-			runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
-		}
-
-		commandExecutor.executeAsync(username, uuid, commandBuilder.buildCommand(runDockerCommand, dto));
-		return uuid;
-	}
-
-	protected abstract FileHandlerCallback getFileHandlerCallback(DockerAction action,
-																  String uuid, String user, String callbackURI);
-
-	private String nameContainer(String user, DockerAction action) {
-		return nameContainer(user, action.toString(), getResourceType());
-	}
-
-	protected String getKeyDirectory() {
-		return configuration.getKeyDirectory();
-	}
-
-	protected String getKeyFilename(String edgeUserName) {
-		return UsernameUtils.replaceWhitespaces(edgeUserName) + KeyAPI.KEY_EXTENTION;
-	}
-
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/base/ExploratoryService.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/base/ExploratoryService.java
deleted file mode 100644
index b15b342..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/base/ExploratoryService.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.resources.base;
-
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.handlers.ExploratoryCallbackHandler;
-import com.epam.dlab.backendapi.service.impl.DockerService;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.exploratory.ExploratoryBaseDTO;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Objects;
-
-@Slf4j
-public class ExploratoryService extends DockerService implements DockerCommands {
-
-	public String action(String username, ExploratoryBaseDTO<?> dto, DockerAction action) throws JsonProcessingException {
-		log.debug("{} exploratory environment", action);
-		String uuid = DockerCommands.generateUUID();
-		folderListenerExecutor.start(configuration.getImagesDirectory(),
-				configuration.getResourceStatusPollTimeout(),
-				getFileHandlerCallback(action, uuid, dto));
-
-		RunDockerCommand runDockerCommand = new RunDockerCommand()
-				.withInteractive()
-				.withName(nameContainer(dto.getEdgeUserName(), action, dto.getExploratoryName()))
-				.withVolumeForRootKeys(configuration.getKeyDirectory())
-				.withVolumeForResponse(configuration.getImagesDirectory())
-				.withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
-				.withResource(getResourceType())
-				.withRequestId(uuid)
-				.withConfKeyName(configuration.getAdminKey())
-				.withImage(dto.getNotebookImage())
-				.withAction(action);
-		if (configuration.getCloudProvider() == CloudProvider.AZURE &&
-				Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
-				!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
-			runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
-		}
-
-		commandExecutor.executeAsync(username, uuid, commandBuilder.buildCommand(runDockerCommand, dto));
-		return uuid;
-	}
-
-	public String getResourceType() {
-		return Directories.NOTEBOOK_LOG_DIRECTORY;
-	}
-
-	private FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, ExploratoryBaseDTO<?> dto) {
-		return new ExploratoryCallbackHandler(selfService, action, uuid, dto.getCloudSettings().getIamUser(),
-				dto.getProject(), dto.getExploratoryName());
-	}
-
-	private String nameContainer(String user, DockerAction action, String name) {
-		return nameContainer(user, action.toString(), "exploratory", name);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/base/InfrastructureService.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/base/InfrastructureService.java
deleted file mode 100644
index 699096a..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/base/InfrastructureService.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * 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.resources.base;
-
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.CommandBuilder;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.folderlistener.FolderListenerExecutor;
-import com.epam.dlab.backendapi.core.response.handlers.ResourcesStatusCallbackHandler;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.UserEnvironmentResources;
-import com.epam.dlab.dto.status.EnvResource;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.process.model.ProcessInfo;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-
-import static com.epam.dlab.backendapi.core.commands.DockerAction.STATUS;
-import static java.util.stream.Collectors.toList;
-
-@Slf4j
-public abstract class InfrastructureService implements DockerCommands {
-	@Inject
-	private RESTService selfService;
-	@Inject
-	private ProvisioningServiceApplicationConfiguration configuration;
-	@Inject
-	private FolderListenerExecutor folderListenerExecutor;
-	@Inject
-	private ICommandExecutor commandExecutor;
-	@Inject
-	private CommandBuilder commandBuilder;
-
-	private static final String CONTAINER_NAME_REGEX_FORMAT = "%s_[^_\\W]+_%s(|_%s)_\\d+";
-
-	public String action(String username, UserEnvironmentResources dto, String iamUser, DockerAction dockerAction) {
-		log.trace("Request the status of resources for user {}: {}", username, dto);
-		String uuid = DockerCommands.generateUUID();
-		folderListenerExecutor.start(configuration.getImagesDirectory(),
-				configuration.getRequestEnvStatusTimeout(),
-				getFileHandlerCallback(dockerAction, uuid, iamUser));
-		try {
-
-			removeResourcesWithRunningContainers(username, dto);
-
-			if (!(dto.getResourceList().getHostList().isEmpty() && dto.getResourceList().getClusterList().isEmpty())) {
-				log.trace("Request the status of resources for user {} after filtering: {}", username, dto);
-				RunDockerCommand runDockerCommand = new RunDockerCommand()
-						.withInteractive()
-						.withName(nameContainer(dto.getEdgeUserName(), STATUS, "resources"))
-						.withVolumeForRootKeys(configuration.getKeyDirectory())
-						.withVolumeForResponse(configuration.getImagesDirectory())
-						.withVolumeForLog(configuration.getDockerLogDirectory(), Directories.EDGE_LOG_DIRECTORY)
-						.withResource(getResourceType())
-						.withRequestId(uuid)
-						.withConfKeyName(configuration.getAdminKey())
-						.withActionStatus(configuration.getEdgeImage());
-				if (configuration.getCloudProvider() == CloudProvider.AZURE &&
-						Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
-						!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
-					runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
-				}
-
-				commandExecutor.executeAsync(username, uuid, commandBuilder.buildCommand(runDockerCommand, dto));
-			} else {
-				log.debug("Skipping calling status command. Resource lists are empty");
-			}
-		} catch (Exception e) {
-			throw new DlabException("Docker's command \"" + getResourceType() + "\" is fail: " + e.getLocalizedMessage
-					(), e);
-		}
-		return uuid;
-	}
-
-	private void removeResourcesWithRunningContainers(String username, UserEnvironmentResources dto)
-			throws Exception {
-
-		final ProcessInfo processInfo = commandExecutor.executeSync(username, DockerCommands.generateUUID(),
-				String.format(DockerCommands
-						.GET_RUNNING_CONTAINERS_FOR_USER, dto.getEdgeUserName()));
-		final String processInfoStdOut = processInfo.getStdOut();
-
-		if (StringUtils.isNoneEmpty(processInfoStdOut)) {
-			final List<String> runningContainerNames = Arrays.asList(processInfoStdOut.split("\n"));
-			log.info("Running containers for users: {}", runningContainerNames);
-			final List<EnvResource> hostList = filter(dto.getEdgeUserName(), runningContainerNames, dto
-					.getResourceList()
-					.getHostList());
-			final List<EnvResource> clusterList = filter(dto.getEdgeUserName(), runningContainerNames, dto
-					.getResourceList()
-					.getClusterList());
-
-			dto.getResourceList().setHostList(hostList);
-			dto.getResourceList().setClusterList(clusterList);
-
-		}
-	}
-
-	private List<EnvResource> filter(String username, List<String> runningContainerNames, List<EnvResource> hostList) {
-		return hostList
-				.stream()
-				.filter(envResource -> hasNotCorrespondingRunningContainer(username, runningContainerNames,
-						envResource))
-				.map(envResource -> new EnvResource().withId(envResource.getId()).withStatus(envResource.getStatus()))
-				.collect(toList());
-	}
-
-	private boolean hasNotCorrespondingRunningContainer(String username, List<String> runningContainerNames,
-														EnvResource
-																envResource) {
-		final String regex = String.format(CONTAINER_NAME_REGEX_FORMAT, username, envResource
-				.getResourceType().name().toLowerCase(), Optional.ofNullable(envResource.getName()).orElse(""));
-		return runningContainerNames.stream().noneMatch(container -> container.matches(regex));
-	}
-
-	protected FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, String user) {
-		return new ResourcesStatusCallbackHandler(selfService, action, uuid, user);
-	}
-
-	private String nameContainer(String user, DockerAction action, String name) {
-		return nameContainer(user, action.toString(), name);
-	}
-
-	public String getResourceType() {
-		return "status";
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/base/KeyResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/base/KeyResource.java
deleted file mode 100644
index bbff7b9..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/base/KeyResource.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.resources.base;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.service.impl.KeyService;
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyDTO;
-import com.epam.dlab.rest.contracts.KeyAPI;
-import com.epam.dlab.util.FileUtils;
-import com.epam.dlab.util.UsernameUtils;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
-import java.io.IOException;
-import java.util.UUID;
-
-/**
- * Provides API for reuploading keys
- */
-@Path("key")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class KeyResource {
-
-	private final KeyService keyService;
-	private final ProvisioningServiceApplicationConfiguration configuration;
-
-	@Inject
-	public KeyResource(KeyService keyService, ProvisioningServiceApplicationConfiguration configuration) {
-		this.keyService = keyService;
-		this.configuration = configuration;
-	}
-
-
-	@Path("/reupload")
-	@POST
-	public String reuploadKey(@Auth UserInfo ui, @DefaultValue("true") @QueryParam("is_primary_reuploading")
-			boolean isPrimaryReuploading, ReuploadKeyDTO dto) throws IOException {
-		if (isPrimaryReuploading) {
-			replaceKeyfile(dto);
-		}
-		keyService.reuploadKeyAction(ui.getName(), dto, DockerAction.REUPLOAD_KEY);
-		return UUID.randomUUID().toString();
-	}
-
-	@GET
-	public String getAdminKey(@Auth UserInfo userInfo) {
-		return keyService.getAdminKey();
-	}
-
-	private void replaceKeyfile(ReuploadKeyDTO dto) throws IOException {
-		String edgeUserName = dto.getEdgeUserName();
-		String filename = UsernameUtils.replaceWhitespaces(edgeUserName) + KeyAPI.KEY_EXTENTION;
-		FileUtils.deleteFile(filename, configuration.getKeyDirectory());
-		FileUtils.saveToFile(filename, configuration.getKeyDirectory(), dto.getContent());
-	}
-
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ComputationalResourceGcp.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ComputationalResourceGcp.java
deleted file mode 100644
index 0db357b..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ComputationalResourceGcp.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * 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.resources.gcp;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.handlers.ComputationalCallbackHandler;
-import com.epam.dlab.backendapi.core.response.handlers.ComputationalConfigure;
-import com.epam.dlab.backendapi.service.impl.DockerService;
-import com.epam.dlab.backendapi.service.impl.SparkClusterService;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.epam.dlab.dto.computational.ComputationalClusterConfigDTO;
-import com.epam.dlab.dto.computational.ComputationalStartDTO;
-import com.epam.dlab.dto.computational.ComputationalStopDTO;
-import com.epam.dlab.dto.gcp.computational.ComputationalCreateGcp;
-import com.epam.dlab.dto.gcp.computational.GcpComputationalTerminateDTO;
-import com.epam.dlab.dto.gcp.computational.SparkComputationalCreateGcp;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.contracts.ComputationalAPI;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-import static com.epam.dlab.backendapi.core.commands.DockerAction.CREATE;
-import static com.epam.dlab.backendapi.core.commands.DockerAction.TERMINATE;
-
-
-@Path("/")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ComputationalResourceGcp extends DockerService implements DockerCommands {
-
-	@Inject
-	private ComputationalConfigure computationalConfigure;
-	@Inject
-	private SparkClusterService sparkClusterService;
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_CREATE_CLOUD_SPECIFIC)
-	public String create(@Auth UserInfo ui, ComputationalCreateGcp dto) {
-		log.debug("Create computational resources {} for user {}: {}", dto.getComputationalName(), ui.getName(), dto);
-		String uuid = DockerCommands.generateUUID();
-		folderListenerExecutor.start(configuration.getImagesDirectory(),
-				configuration.getResourceStatusPollTimeout(),
-				getFileHandlerCallback(CREATE, uuid, dto));
-		try {
-			commandExecutor.executeAsync(
-					ui.getName(),
-					uuid,
-					commandBuilder.buildCommand(
-							new RunDockerCommand()
-									.withInteractive()
-									.withName(nameContainer(dto.getEdgeUserName(), CREATE,
-											dto.getExploratoryName(), dto.getComputationalName()))
-									.withVolumeForRootKeys(configuration.getKeyDirectory())
-									.withVolumeForResponse(configuration.getImagesDirectory())
-									.withVolumeForLog(configuration.getDockerLogDirectory(), DataEngineType
-											.CLOUD_SERVICE.getName())
-									.withResource(DataEngineType.CLOUD_SERVICE.getName())
-									.withRequestId(uuid)
-									.withConfKeyName(configuration.getAdminKey())
-									.withActionCreate(DataEngineType.getDockerImageName(DataEngineType.CLOUD_SERVICE)),
-							dto
-					)
-			);
-		} catch (Exception t) {
-			throw new DlabException("Could not create computational resource cluster", t);
-		}
-		return uuid;
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC)
-	public String terminate(@Auth UserInfo ui, GcpComputationalTerminateDTO dto) {
-
-		log.debug("Terminate computational resources {} for user {}: {}", dto.getComputationalName(), ui.getName(),
-				dto);
-		String uuid = DockerCommands.generateUUID();
-		folderListenerExecutor.start(configuration.getImagesDirectory(),
-				configuration.getResourceStatusPollTimeout(),
-				getFileHandlerCallback(TERMINATE, uuid, dto));
-		try {
-			commandExecutor.executeAsync(
-					ui.getName(),
-					uuid,
-					commandBuilder.buildCommand(
-							new RunDockerCommand()
-									.withInteractive()
-									.withName(nameContainer(dto.getEdgeUserName(), TERMINATE,
-											dto.getExploratoryName(), dto.getComputationalName()))
-									.withVolumeForRootKeys(configuration.getKeyDirectory())
-									.withVolumeForResponse(configuration.getImagesDirectory())
-									.withVolumeForLog(configuration.getDockerLogDirectory(), DataEngineType
-											.CLOUD_SERVICE.getName())
-									.withResource(DataEngineType.CLOUD_SERVICE.getName())
-									.withRequestId(uuid)
-									.withConfKeyName(configuration.getAdminKey())
-									.withActionTerminate(DataEngineType.getDockerImageName(DataEngineType
-											.CLOUD_SERVICE)),
-							dto
-					)
-			);
-		} catch (JsonProcessingException t) {
-			throw new DlabException("Could not terminate computational resources cluster", t);
-		}
-
-		return uuid;
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_CREATE_SPARK)
-	public String createSparkCluster(@Auth UserInfo ui, SparkComputationalCreateGcp dto) {
-		log.debug("Create computational Spark resources {} for user {}: {}", dto.getComputationalName(), ui.getName(),
-				dto);
-
-		return sparkClusterService.create(ui, dto);
-	}
-
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_TERMINATE_SPARK)
-	public String terminateSparkCluster(@Auth UserInfo ui, GcpComputationalTerminateDTO dto) {
-		log.debug("Terminate computational Spark resources {} for user {}: {}", dto.getComputationalName(), ui.getName
-				(), dto);
-
-		return sparkClusterService.terminate(ui, dto);
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_STOP_SPARK)
-	public String stopSparkCluster(@Auth UserInfo ui, ComputationalStopDTO dto) {
-		log.debug("Stop computational Spark resources {} for user {}: {}",
-				dto.getComputationalName(), ui.getName(), dto);
-
-		return sparkClusterService.stop(ui, dto);
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_START_SPARK)
-	public String startSparkCluster(@Auth UserInfo ui, ComputationalStartDTO dto) {
-		log.debug("Start computational Spark resource {} for user {}: {}",
-				dto.getComputationalName(), ui.getName(), dto);
-
-		return sparkClusterService.start(ui, dto);
-	}
-
-	@POST
-	@Path(ComputationalAPI.COMPUTATIONAL_RECONFIGURE_SPARK)
-	public String reconfigureSparkCluster(@Auth UserInfo ui, ComputationalClusterConfigDTO config) {
-		log.debug("User is reconfiguring {} spark cluster for exploratory {}", ui.getName(),
-				config.getComputationalName(), config.getNotebookInstanceName());
-		return sparkClusterService.updateConfig(ui, config);
-	}
-
-	private FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, ComputationalBase<?> dto) {
-		return new ComputationalCallbackHandler(computationalConfigure, selfService, action, uuid, dto);
-	}
-
-	private String nameContainer(String user, DockerAction action, String exploratoryName, String name) {
-		return nameContainer(user, action.toString(), "computational", exploratoryName, name);
-	}
-
-	@Override
-	public String getResourceType() {
-		return Directories.DATA_ENGINE_SERVICE_LOG_DIRECTORY;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/EdgeResourceGcp.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/EdgeResourceGcp.java
deleted file mode 100644
index 4509bff..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/EdgeResourceGcp.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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.resources.gcp;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.response.handlers.EdgeCallbackHandler;
-import com.epam.dlab.backendapi.resources.base.EdgeService;
-import com.epam.dlab.dto.ResourceSysBaseDTO;
-import com.epam.dlab.dto.base.keyload.UploadFileResult;
-import com.epam.dlab.dto.gcp.edge.EdgeInfoGcp;
-import com.epam.dlab.dto.gcp.keyload.UploadFileGcp;
-import com.epam.dlab.util.FileUtils;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import java.io.IOException;
-
-import static com.epam.dlab.rest.contracts.ApiCallbacks.EDGE;
-import static com.epam.dlab.rest.contracts.ApiCallbacks.KEY_LOADER;
-import static com.epam.dlab.rest.contracts.ApiCallbacks.STATUS_URI;
-
-/**
- * Provides API to manage Edge node on GCP
- */
-@Path("infrastructure/edge")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class EdgeResourceGcp extends EdgeService {
-
-	public EdgeResourceGcp() {
-		log.info("{} is initialized", getClass().getSimpleName());
-	}
-
-	@POST
-	@Path("/create")
-	public String create(@Auth UserInfo ui, UploadFileGcp dto) throws IOException {
-		FileUtils.saveToFile(getKeyFilename(dto.getEdge().getEdgeUserName()), getKeyDirectory(), dto.getContent());
-		return action(ui.getName(), dto.getEdge(), dto.getEdge().getCloudSettings().getIamUser(), KEY_LOADER,
-				DockerAction.CREATE);
-	}
-
-	@POST
-	@Path("/start")
-	public String start(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
-		return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI, DockerAction.START);
-	}
-
-	@POST
-	@Path("/stop")
-	public String stop(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
-		return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI, DockerAction.STOP);
-	}
-
-
-	@POST
-	@Path("/terminate")
-	public String terminate(@Auth UserInfo ui, ResourceSysBaseDTO<?> dto) throws JsonProcessingException {
-		return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), EDGE + STATUS_URI,
-				DockerAction.TERMINATE);
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	protected FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, String user, String
-			callbackURI) {
-		return new EdgeCallbackHandler(selfService, action, uuid, user, callbackURI,
-				EdgeInfoGcp.class,
-				UploadFileResult.class);
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ExploratoryResourceGcp.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ExploratoryResourceGcp.java
deleted file mode 100644
index 778ee0c..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ExploratoryResourceGcp.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.resources.gcp;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.resources.base.ExploratoryService;
-import com.epam.dlab.dto.exploratory.ExploratoryActionDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
-import com.epam.dlab.dto.gcp.exploratory.ExploratoryCreateGcp;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-@Path("/exploratory")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class ExploratoryResourceGcp {
-
-    @Inject
-    private ExploratoryService exploratoryService;
-
-
-    @Path("/create")
-    @POST
-    public String create(@Auth UserInfo ui, ExploratoryCreateGcp dto) throws JsonProcessingException {
-        return exploratoryService.action(ui.getName(), dto, DockerAction.CREATE);
-    }
-
-    @Path("/start")
-    @POST
-    public String start(@Auth UserInfo ui, ExploratoryGitCredsUpdateDTO dto) throws JsonProcessingException {
-        return exploratoryService.action(ui.getName(), dto, DockerAction.START);
-    }
-
-    @Path("/terminate")
-    @POST
-    public String terminate(@Auth UserInfo ui, ExploratoryActionDTO<?> dto) throws JsonProcessingException {
-        return exploratoryService.action(ui.getName(), dto, DockerAction.TERMINATE);
-    }
-
-    @Path("/stop")
-    @POST
-    public String stop(@Auth UserInfo ui, ExploratoryActionDTO<?> dto) throws JsonProcessingException {
-        return exploratoryService.action(ui.getName(), dto, DockerAction.STOP);
-    }
-
-    @Path("/reconfigure_spark")
-    @POST
-    public String reconfigureSpark(@Auth UserInfo ui, ExploratoryReconfigureSparkClusterActionDTO dto) throws JsonProcessingException {
-        return exploratoryService.action(ui.getName(), dto, DockerAction.RECONFIGURE_SPARK);
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/InfrastructureResourceGcp.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/InfrastructureResourceGcp.java
deleted file mode 100644
index be80c02..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/InfrastructureResourceGcp.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.resources.gcp;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.resources.base.InfrastructureService;
-import com.epam.dlab.dto.UserEnvironmentResources;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-@Path("/infrastructure")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class InfrastructureResourceGcp extends InfrastructureService {
-    public InfrastructureResourceGcp() {
-        log.info("{} is initialized", getClass().getSimpleName());
-    }
-
-    @Path("/status")
-    @POST
-    public String status(@Auth UserInfo ui, UserEnvironmentResources dto) {
-        return action(ui.getName(), dto, dto.getCloudSettings().getIamUser(), DockerAction.STATUS);
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/BucketService.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/BucketService.java
deleted file mode 100644
index 47b001b..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/BucketService.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.dto.bucket.BucketDTO;
-
-import javax.servlet.http.HttpServletResponse;
-import java.io.InputStream;
-import java.util.List;
-
-public interface BucketService {
-    String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
-
-    List<BucketDTO> getObjects(String bucket);
-
-    void uploadObject(String bucket, String object, InputStream stream, String contentType, long fileSize);
-
-    void uploadFolder(UserInfo userInfo, String bucket, String folder);
-
-    void downloadObject(String bucket, String object, HttpServletResponse resp);
-
-    void deleteObjects(String bucket, List<String> objects);
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/CheckInactivityService.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/CheckInactivityService.java
deleted file mode 100644
index 50d8e00..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/CheckInactivityService.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.dto.computational.ComputationalCheckInactivityDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryCheckInactivityAction;
-
-public interface CheckInactivityService {
-	String checkComputationalInactivity(String userName, ComputationalCheckInactivityDTO dto);
-
-	String checkExploratoryInactivity(String userName, ExploratoryCheckInactivityAction dto);
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
deleted file mode 100644
index 8770591..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.dto.project.ProjectActionDTO;
-import com.epam.dlab.dto.project.ProjectCreateDTO;
-
-public interface ProjectService {
-
-	String create(UserInfo userInfo, ProjectCreateDTO projectCreateDTO);
-
-	String terminate(UserInfo userInfo, ProjectActionDTO dto);
-
-	String start(UserInfo userInfo, ProjectActionDTO dto);
-
-	String stop(UserInfo userInfo, ProjectActionDTO dto);
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/RestoreCallbackHandlerService.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/RestoreCallbackHandlerService.java
deleted file mode 100644
index 73b908a..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/RestoreCallbackHandlerService.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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;
-
-@FunctionalInterface
-public interface RestoreCallbackHandlerService {
-	void restore();
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/CheckInactivityServiceImpl.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/CheckInactivityServiceImpl.java
deleted file mode 100644
index 59e67b4..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/CheckInactivityServiceImpl.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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.core.Directories;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.handlers.CheckInactivityCallbackHandler;
-import com.epam.dlab.backendapi.service.CheckInactivityService;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.ResourceBaseDTO;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.computational.ComputationalCheckInactivityDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryCheckInactivityAction;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.google.inject.Singleton;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Objects;
-
-@Slf4j
-@Singleton
-public class CheckInactivityServiceImpl extends DockerService implements CheckInactivityService, DockerCommands {
-
-
-	@Override
-	public String checkComputationalInactivity(String userName, ComputationalCheckInactivityDTO dto) {
-		String uuid = DockerCommands.generateUUID();
-		startComputationalCallbackListener(userName, dto, uuid);
-		final RunDockerCommand runDockerCommand = new RunDockerCommand()
-				.withInteractive()
-				.withRemove()
-				.withName(nameContainer(uuid, DockerAction.CHECK_INACTIVITY.toString()))
-				.withVolumeForRootKeys(configuration.getKeyDirectory())
-				.withVolumeForResponse(configuration.getKeyLoaderDirectory())
-				.withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
-				.withResource(DataEngineType.fromDockerImageName(dto.getImage()) == DataEngineType.SPARK_STANDALONE ?
-						Directories.DATA_ENGINE_LOG_DIRECTORY :
-						Directories.DATA_ENGINE_SERVICE_LOG_DIRECTORY)
-				.withRequestId(uuid)
-				.withConfKeyName(configuration.getAdminKey())
-				.withImage(dto.getNotebookImage())
-				.withAction(DockerAction.CHECK_INACTIVITY);
-		if (configuration.getCloudProvider() == CloudProvider.AZURE &&
-				Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
-				!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
-			runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
-		}
-
-		runDockerCmd(userName, uuid, runDockerCommand, dto);
-		return uuid;
-	}
-
-	@Override
-	public String checkExploratoryInactivity(String userName, ExploratoryCheckInactivityAction dto) {
-		String uuid = DockerCommands.generateUUID();
-		startExploratoryCallbackListener(userName, dto, uuid);
-		final RunDockerCommand runDockerCommand = new RunDockerCommand()
-				.withInteractive()
-				.withRemove()
-				.withName(nameContainer(uuid, DockerAction.CHECK_INACTIVITY.toString()))
-				.withVolumeForRootKeys(configuration.getKeyDirectory())
-				.withVolumeForResponse(configuration.getKeyLoaderDirectory())
-				.withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
-				.withResource(Directories.NOTEBOOK_LOG_DIRECTORY)
-				.withRequestId(uuid)
-				.withConfKeyName(configuration.getAdminKey())
-				.withImage(dto.getNotebookImage())
-				.withAction(DockerAction.CHECK_INACTIVITY);
-		if (configuration.getCloudProvider() == CloudProvider.AZURE &&
-				Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
-				!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
-			runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
-		}
-
-		runDockerCmd(userName, uuid, runDockerCommand, dto);
-		return uuid;
-	}
-
-	private void startComputationalCallbackListener(String userName, ComputationalCheckInactivityDTO dto,
-													String uuid) {
-		final CheckInactivityCallbackHandler handler = new CheckInactivityCallbackHandler(
-				selfService, ApiCallbacks.CHECK_INACTIVITY_COMPUTATIONAL_URI, userName, uuid,
-				dto.getExploratoryName(), dto.getComputationalName());
-		folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
-				configuration.getKeyLoaderPollTimeout(), handler);
-	}
-
-	private void startExploratoryCallbackListener(String userName, ExploratoryCheckInactivityAction dto, String uuid) {
-		final CheckInactivityCallbackHandler handler = new CheckInactivityCallbackHandler(
-				selfService, ApiCallbacks.CHECK_INACTIVITY_EXPLORATORY_URI, userName, uuid,
-				dto.getExploratoryName());
-		folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
-				configuration.getKeyLoaderPollTimeout(), handler);
-	}
-
-	private void runDockerCmd(String userName, String uuid, RunDockerCommand dockerCmd, ResourceBaseDTO<?> dto) {
-		try {
-			final String command = commandBuilder.buildCommand(dockerCmd, dto);
-			log.trace("Docker command: {}", command);
-			commandExecutor.executeAsync(userName, uuid, command);
-		} catch (Exception e) {
-			log.error("Exception occured during reuploading key: {} for command {}", e.getLocalizedMessage(),
-					dockerCmd.toCMD(), e);
-		}
-	}
-
-	@Override
-	public String getResourceType() {
-		return Directories.NOTEBOOK_LOG_DIRECTORY;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/DockerService.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/DockerService.java
deleted file mode 100644
index 5e5a20a..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/DockerService.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.commands.CommandBuilder;
-import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
-import com.epam.dlab.backendapi.core.response.folderlistener.FolderListenerExecutor;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.inject.Inject;
-
-public abstract class DockerService {
-
-	@Inject
-	protected ProvisioningServiceApplicationConfiguration configuration;
-	@Inject
-	protected FolderListenerExecutor folderListenerExecutor;
-	@Inject
-	protected ICommandExecutor commandExecutor;
-	@Inject
-	protected CommandBuilder commandBuilder;
-	@Inject
-	protected RESTService selfService;
-
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/KeyService.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/KeyService.java
deleted file mode 100644
index 5d650da..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/KeyService.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.handlers.ReuploadKeyCallbackHandler;
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyCallbackDTO;
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.model.ResourceData;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-
-import static java.lang.String.format;
-import static java.nio.file.Files.readAllBytes;
-import static java.nio.file.Paths.get;
-
-@Slf4j
-@Singleton
-public class KeyService extends DockerService implements DockerCommands {
-
-	private static final String REUPLOAD_KEY_ACTION = "reupload_key";
-
-	private final ProvisioningServiceApplicationConfiguration conf;
-
-	@Inject
-	public KeyService(ProvisioningServiceApplicationConfiguration conf) {
-		this.conf = conf;
-	}
-
-
-	public void reuploadKeyAction(String userName, ReuploadKeyDTO dto, DockerAction action) {
-		log.debug("{} for edge user {}", action, dto.getEdgeUserName());
-
-		long count = dto.getResources()
-				.stream()
-				.map(resourceData -> buildCallbackDTO(resourceData, getUuid(), dto))
-				.peek(callbackDto -> startCallbackListener(userName, callbackDto))
-				.peek(callbackDto ->
-						runDockerCmd(userName, callbackDto.getId(), buildRunDockerCommand(callbackDto, action),
-								buildDockerCommandDTO(callbackDto)))
-				.count();
-		log.debug("Executed {} Docker commands", count);
-	}
-
-	public String getAdminKey() {
-		try {
-			return new String(readAllBytes(get(format("%s/%s.pem", conf.getKeyDirectory(), conf.getAdminKey()))));
-		} catch (IOException e) {
-			log.error("Can not read admin key: {}", e.getMessage());
-			throw new DlabException("Can not read admin key: " + e.getMessage(), e);
-		}
-	}
-
-	private String getUuid() {
-		return DockerCommands.generateUUID();
-	}
-
-	private void runDockerCmd(String userName, String uuid, RunDockerCommand runDockerCommand,
-							  ReuploadKeyCallbackDTO callbackDto) {
-		try {
-			final String command = commandBuilder.buildCommand(runDockerCommand, callbackDto);
-			log.trace("Docker command: {}", command);
-			commandExecutor.executeAsync(userName, uuid, command);
-		} catch (Exception e) {
-			log.error("Exception occured during reuploading key: {} for command {}", e.getLocalizedMessage(),
-					runDockerCommand.toCMD(), e);
-		}
-	}
-
-	private void startCallbackListener(String userName, ReuploadKeyCallbackDTO dto) {
-		folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
-				configuration.getKeyLoaderPollTimeout(),
-				new ReuploadKeyCallbackHandler(selfService, ApiCallbacks.REUPLOAD_KEY_URI,
-						userName, dto));
-	}
-
-	@Override
-	public String getResourceType() {
-		return Directories.EDGE_LOG_DIRECTORY;
-	}
-
-	private RunDockerCommand buildRunDockerCommand(ReuploadKeyCallbackDTO callbackDto, DockerAction action) {
-		return new RunDockerCommand()
-				.withInteractive()
-				.withName(getContainerName(callbackDto))
-				.withVolumeForRootKeys(configuration.getKeyDirectory())
-				.withVolumeForResponse(configuration.getKeyLoaderDirectory())
-				.withVolumeForLog(configuration.getDockerLogDirectory(), getResourceType())
-				.withResource(callbackDto.getResource().getResourceType().toString())
-				.withRequestId(callbackDto.getId())
-				.withConfKeyName(configuration.getAdminKey())
-				.withImage(configuration.getEdgeImage())
-				.withAction(action);
-	}
-
-	private ReuploadKeyCallbackDTO buildCallbackDTO(ResourceData resource, String uuid, ReuploadKeyDTO dto) {
-		return new ReuploadKeyCallbackDTO()
-				.withId(uuid)
-				.withEdgeUserName(dto.getEdgeUserName())
-				.withServiceBaseName(dto.getServiceBaseName())
-				.withConfOsFamily(dto.getConfOsFamily())
-				.withResourceId(resource.getResourceId())
-				.withResource(resource);
-	}
-
-	private ReuploadKeyCallbackDTO buildDockerCommandDTO(ReuploadKeyCallbackDTO dto) {
-		return new ReuploadKeyCallbackDTO()
-				.withEdgeUserName(dto.getEdgeUserName())
-				.withServiceBaseName(dto.getServiceBaseName())
-				.withConfOsFamily(dto.getConfOsFamily())
-				.withResourceId(dto.getResourceId());
-	}
-
-	private String getContainerName(ReuploadKeyCallbackDTO callbackDto) {
-		return nameContainer(callbackDto.getEdgeUserName(), REUPLOAD_KEY_ACTION,
-				callbackDto.getResource().getResourceType().toString(),
-				callbackDto.getResource().getResourceId());
-	}
-
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
deleted file mode 100644
index 5f24a1e..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.commands.CommandBuilder;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.folderlistener.FolderListenerExecutor;
-import com.epam.dlab.backendapi.core.response.handlers.ProjectCallbackHandler;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.ResourceBaseDTO;
-import com.epam.dlab.dto.aws.edge.EdgeInfoAws;
-import com.epam.dlab.dto.azure.edge.EdgeInfoAzure;
-import com.epam.dlab.dto.gcp.edge.EdgeInfoGcp;
-import com.epam.dlab.dto.project.ProjectActionDTO;
-import com.epam.dlab.dto.project.ProjectCreateDTO;
-import com.epam.dlab.rest.client.RESTService;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Objects;
-
-@Slf4j
-public class ProjectServiceImpl implements ProjectService {
-	private static final String PROJECT_IMAGE = "docker.dlab-project";
-	private static final String EDGE_IMAGE = "docker.dlab-edge";
-	private static final String CALLBACK_URI = "/api/project/status";
-
-	protected final RESTService selfService;
-	private final ProvisioningServiceApplicationConfiguration configuration;
-	private final FolderListenerExecutor folderListenerExecutor;
-	private final ICommandExecutor commandExecutor;
-	private final CommandBuilder commandBuilder;
-
-	@Inject
-	public ProjectServiceImpl(RESTService selfService, ProvisioningServiceApplicationConfiguration configuration,
-	                          FolderListenerExecutor folderListenerExecutor, ICommandExecutor commandExecutor, CommandBuilder commandBuilder) {
-		this.selfService = selfService;
-		this.configuration = configuration;
-		this.folderListenerExecutor = folderListenerExecutor;
-		this.commandExecutor = commandExecutor;
-		this.commandBuilder = commandBuilder;
-	}
-
-	@Override
-	public String create(UserInfo userInfo, ProjectCreateDTO dto) {
-		return executeDocker(userInfo, dto, DockerAction.CREATE, dto.getName(), "project", PROJECT_IMAGE,
-				dto.getEndpoint());
-	}
-
-	@Override
-	public String terminate(UserInfo userInfo, ProjectActionDTO dto) {
-		return executeDocker(userInfo, dto, DockerAction.TERMINATE, dto.getName(), "project", PROJECT_IMAGE,
-				dto.getEndpoint());
-	}
-
-	@Override
-	public String start(UserInfo userInfo, ProjectActionDTO dto) {
-		return executeDocker(userInfo, dto, DockerAction.START, dto.getName(), "edge", EDGE_IMAGE, dto.getEndpoint());
-	}
-
-	@Override
-	public String stop(UserInfo userInfo, ProjectActionDTO dto) {
-		return executeDocker(userInfo, dto, DockerAction.STOP, dto.getName(), "edge", EDGE_IMAGE, dto.getEndpoint());
-	}
-
-	private String executeDocker(UserInfo userInfo, ResourceBaseDTO dto, DockerAction action, String projectName,
-	                             String resourceType, String image, String endpoint) {
-		String uuid = DockerCommands.generateUUID();
-
-		folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
-				configuration.getKeyLoaderPollTimeout(),
-				new ProjectCallbackHandler(selfService, userInfo.getName(), uuid,
-						action, CALLBACK_URI, projectName, getEdgeClass(), endpoint));
-
-		RunDockerCommand runDockerCommand = new RunDockerCommand()
-				.withInteractive()
-				.withName(String.join("_", userInfo.getSimpleName(), projectName, resourceType, action.toString(),
-						Long.toString(System.currentTimeMillis())))
-				.withVolumeForRootKeys(configuration.getKeyDirectory())
-				.withVolumeForResponse(configuration.getKeyLoaderDirectory())
-				.withVolumeForLog(configuration.getDockerLogDirectory(), resourceType)
-				.withResource(resourceType)
-				.withRequestId(uuid)
-				.withConfKeyName(configuration.getAdminKey())
-				.withImage(image)
-				.withAction(action);
-		if (configuration.getCloudProvider() == CloudProvider.AZURE &&
-				Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
-				!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
-			runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
-		}
-
-		try {
-			commandExecutor.executeAsync(userInfo.getName(), uuid, commandBuilder.buildCommand(runDockerCommand, dto));
-		} catch (JsonProcessingException e) {
-			log.error("Something went wrong. Reason {}", e.getMessage(), e);
-		}
-		return uuid;
-	}
-
-	private <T> Class<T> getEdgeClass() {
-		if (configuration.getCloudProvider() == CloudProvider.AWS) {
-			return (Class<T>) EdgeInfoAws.class;
-		} else if (configuration.getCloudProvider() == CloudProvider.AZURE) {
-			return (Class<T>) EdgeInfoAzure.class;
-		} else if (configuration.getCloudProvider() == CloudProvider.GCP) {
-			return (Class<T>) EdgeInfoGcp.class;
-		}
-		throw new IllegalArgumentException();
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/RestoreCallbackHandlerServiceImpl.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/RestoreCallbackHandlerServiceImpl.java
deleted file mode 100644
index 690e40a..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/RestoreCallbackHandlerServiceImpl.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.core.response.folderlistener.FolderListenerExecutor;
-import com.epam.dlab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
-import com.epam.dlab.backendapi.service.RestoreCallbackHandlerService;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import io.dropwizard.lifecycle.Managed;
-import io.dropwizard.util.Duration;
-import lombok.extern.slf4j.Slf4j;
-
-@Singleton
-@Slf4j
-public class RestoreCallbackHandlerServiceImpl implements Managed, RestoreCallbackHandlerService {
-
-	@Inject
-	private CallbackHandlerDao callbackHandlerDao;
-	@Inject
-	private FolderListenerExecutor folderListenerExecutor;
-
-	@Override
-	public void start() {
-		restore();
-	}
-
-	@Override
-	public void stop() {
-		log.info("RestoreCallbackHandlerServiceImpl stopped");
-	}
-
-	public void restore() {
-		log.info("Restoring callback handlers");
-		callbackHandlerDao.findAll().forEach(persistentFileHandler ->
-				folderListenerExecutor.start(persistentFileHandler.getDirectory(),
-						Duration.milliseconds(persistentFileHandler.getTimeout()),
-						persistentFileHandler.getHandler()));
-		log.info("Successfully restored file handlers");
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/SparkClusterService.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/SparkClusterService.java
deleted file mode 100644
index ce73096..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/SparkClusterService.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.core.Directories;
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.commands.DockerCommands;
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import com.epam.dlab.backendapi.core.response.handlers.ComputationalCallbackHandler;
-import com.epam.dlab.backendapi.core.response.handlers.ComputationalConfigure;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.epam.dlab.dto.computational.ComputationalClusterConfigDTO;
-import com.epam.dlab.dto.computational.ComputationalStartDTO;
-import com.epam.dlab.dto.computational.ComputationalStopDTO;
-import com.epam.dlab.dto.computational.ComputationalTerminateDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-import java.util.Objects;
-
-import static com.epam.dlab.backendapi.core.commands.DockerAction.CREATE;
-import static com.epam.dlab.backendapi.core.commands.DockerAction.RECONFIGURE_SPARK;
-import static com.epam.dlab.backendapi.core.commands.DockerAction.START;
-import static com.epam.dlab.backendapi.core.commands.DockerAction.STOP;
-import static com.epam.dlab.backendapi.core.commands.DockerAction.TERMINATE;
-
-@Singleton
-public class SparkClusterService extends DockerService implements DockerCommands {
-
-	private static final DataEngineType SPARK_ENGINE = DataEngineType.SPARK_STANDALONE;
-
-	@Inject
-	private ComputationalConfigure computationalConfigure;
-
-	public String create(UserInfo ui, ComputationalBase<?> dto) {
-		return action(ui, dto, CREATE);
-	}
-
-	public String terminate(UserInfo ui, ComputationalTerminateDTO dto) {
-		return action(ui, dto, TERMINATE);
-	}
-
-	public String stop(UserInfo ui, ComputationalStopDTO dto) {
-		return action(ui, dto, STOP);
-	}
-
-	public String start(UserInfo ui, ComputationalStartDTO dto) {
-		return action(ui, dto, START);
-	}
-
-	public String updateConfig(UserInfo ui, ComputationalClusterConfigDTO clusterConfigDTO) {
-		String uuid = DockerCommands.generateUUID();
-		folderListenerExecutor.start(configuration.getImagesDirectory(),
-				configuration.getResourceStatusPollTimeout(),
-				getFileHandlerCallback(RECONFIGURE_SPARK, uuid, clusterConfigDTO));
-		runReconfigureSparkDockerCommand(ui, clusterConfigDTO, uuid);
-		return uuid;
-	}
-
-	private void runReconfigureSparkDockerCommand(UserInfo ui, ComputationalClusterConfigDTO clusterConfigDTO,
-												  String uuid) {
-		try {
-			final RunDockerCommand runDockerCommand = new RunDockerCommand()
-					.withInteractive()
-					.withName(nameContainer(clusterConfigDTO.getEdgeUserName(), RECONFIGURE_SPARK,
-							clusterConfigDTO.getExploratoryName(),
-							clusterConfigDTO.getComputationalName()))
-					.withVolumeForRootKeys(configuration.getKeyDirectory())
-					.withVolumeForResponse(configuration.getImagesDirectory())
-					.withVolumeForLog(configuration.getDockerLogDirectory(), SPARK_ENGINE.getName())
-					.withResource(SPARK_ENGINE.getName())
-					.withRequestId(uuid)
-					.withConfKeyName(configuration.getAdminKey())
-					.withImage(DataEngineType.getDockerImageName(SPARK_ENGINE))
-					.withAction(RECONFIGURE_SPARK);
-			if (configuration.getCloudProvider() == CloudProvider.AZURE &&
-					Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
-					!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
-				runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
-			}
-
-			commandExecutor.executeAsync(ui.getName(), uuid, commandBuilder.buildCommand(runDockerCommand,
-					clusterConfigDTO));
-		} catch (JsonProcessingException e) {
-			throw new DlabException("Could not" + RECONFIGURE_SPARK.toString() + "computational resources cluster", e);
-		}
-	}
-
-	private String action(UserInfo ui, ComputationalBase<?> dto, DockerAction action) {
-		String uuid = DockerCommands.generateUUID();
-		folderListenerExecutor.start(configuration.getImagesDirectory(),
-				configuration.getResourceStatusPollTimeout(),
-				getFileHandlerCallback(action, uuid, dto));
-		try {
-			final RunDockerCommand runDockerCommand = new RunDockerCommand()
-					.withInteractive()
-					.withName(nameContainer(dto.getEdgeUserName(), action, dto.getExploratoryName(),
-							dto.getComputationalName()))
-					.withVolumeForRootKeys(configuration.getKeyDirectory())
-					.withVolumeForResponse(configuration.getImagesDirectory())
-					.withVolumeForLog(configuration.getDockerLogDirectory(), SPARK_ENGINE.getName())
-					.withResource(SPARK_ENGINE.getName())
-					.withRequestId(uuid)
-					.withConfKeyName(configuration.getAdminKey())
-					.withImage(DataEngineType.getDockerImageName(SPARK_ENGINE))
-					.withAction(action);
-			if (configuration.getCloudProvider() == CloudProvider.AZURE &&
-					Objects.nonNull(configuration.getCloudConfiguration().getAzureAuthFile()) &&
-					!configuration.getCloudConfiguration().getAzureAuthFile().isEmpty()) {
-				runDockerCommand.withVolumeFoAzureAuthFile(configuration.getCloudConfiguration().getAzureAuthFile());
-			}
-
-			commandExecutor.executeAsync(ui.getName(), uuid, commandBuilder.buildCommand(runDockerCommand, dto));
-		} catch (JsonProcessingException e) {
-			throw new DlabException("Could not" + action.toString() + "computational resources cluster", e);
-		}
-
-		return uuid;
-	}
-
-	private FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, ComputationalBase<?> dto) {
-		return new ComputationalCallbackHandler(computationalConfigure, selfService, action, uuid, dto);
-	}
-
-	private String nameContainer(String user, DockerAction action, String exploratoryName, String name) {
-		return nameContainer(user, action.toString(), "computational", exploratoryName, name);
-	}
-
-	@Override
-	public String getResourceType() {
-		return Directories.DATA_ENGINE_LOG_DIRECTORY;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/aws/BucketServiceAwsImpl.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/aws/BucketServiceAwsImpl.java
deleted file mode 100644
index 6c5673d..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/aws/BucketServiceAwsImpl.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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.aws;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.BucketService;
-import com.epam.dlab.dto.bucket.BucketDTO;
-import com.epam.dlab.exceptions.DlabException;
-import lombok.extern.slf4j.Slf4j;
-import software.amazon.awssdk.core.sync.RequestBody;
-import software.amazon.awssdk.core.sync.ResponseTransformer;
-import software.amazon.awssdk.services.s3.S3Client;
-import software.amazon.awssdk.services.s3.model.Delete;
-import software.amazon.awssdk.services.s3.model.DeleteObjectsRequest;
-import software.amazon.awssdk.services.s3.model.GetObjectRequest;
-import software.amazon.awssdk.services.s3.model.ListObjectsRequest;
-import software.amazon.awssdk.services.s3.model.ObjectIdentifier;
-import software.amazon.awssdk.services.s3.model.PutObjectRequest;
-import software.amazon.awssdk.services.s3.model.S3Object;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletResponse;
-import java.io.InputStream;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Slf4j
-public class BucketServiceAwsImpl implements BucketService {
-
-    @Override
-    public List<BucketDTO> getObjects(String bucket) {
-        try (S3Client s3 = S3Client.create()) {
-	        ListObjectsRequest getRequest = ListObjectsRequest
-			        .builder()
-			        .bucket(bucket)
-			        .build();
-
-	        return s3.listObjects(getRequest).contents()
-			        .stream()
-			        .map(o -> toBucketDTO(bucket, o))
-			        .collect(Collectors.toList());
-        } catch (Exception e) {
-	        log.error("Cannot retrieve objects from bucket {}. Reason: {}", bucket, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot retrieve objects from bucket %s. Reason: %s", bucket, e.getMessage()));
-        }
-    }
-
-    @Override
-    public void uploadObject(String bucket, String object, InputStream stream, String contentType, long fileSize) {
-        log.info("Uploading file {} to bucket {}", object, bucket);
-	    try (S3Client s3 = S3Client.create()) {
-		    PutObjectRequest uploadRequest = PutObjectRequest
-				    .builder()
-				    .bucket(bucket)
-				    .key(object)
-				    .contentType(contentType)
-				    .build();
-		    s3.putObject(uploadRequest, RequestBody.fromInputStream(stream, fileSize));
-	    } catch (Exception e) {
-		    log.error("Cannot upload object {} to bucket {}. Reason: {}", object, bucket, e.getMessage(), e);
-		    throw new DlabException(String.format("Cannot upload object %s to bucket %s. Reason: %s", object, bucket, e.getMessage()));
-        }
-        log.info("Finished uploading file {} to bucket {}", object, bucket);
-    }
-
-    @Override
-    public void uploadFolder(UserInfo userInfo, String bucket, String folder) {
-        log.info("Uploading folder {} to bucket {}", folder, bucket);
-	    try (S3Client s3 = S3Client.create()) {
-		    PutObjectRequest uploadRequest = PutObjectRequest
-				    .builder()
-				    .bucket(bucket)
-				    .key(folder)
-				    .build();
-		    s3.putObject(uploadRequest, RequestBody.empty());
-	    } catch (Exception e) {
-		    log.error("Cannot upload folder {} to bucket {}. Reason: {}", folder, bucket, e.getMessage(), e);
-		    throw new DlabException(String.format("Cannot upload folder %s to bucket %s. Reason: %s", folder, bucket, e.getMessage()));
-	    }
-        log.info("Finished uploading folder {} to bucket {}", folder, bucket);
-    }
-
-    @Override
-    public void downloadObject(String bucket, String object, HttpServletResponse resp) {
-        log.info("Downloading file {} from bucket {}", object, bucket);
-	    try (ServletOutputStream outputStream = resp.getOutputStream(); S3Client s3 = S3Client.create()) {
-		    GetObjectRequest downloadRequest = GetObjectRequest
-				    .builder()
-				    .bucket(bucket)
-				    .key(object)
-				    .build();
-		    s3.getObject(downloadRequest, ResponseTransformer.toOutputStream(outputStream));
-	    } catch (Exception e) {
-		    log.error("Cannot download object {} from bucket {}. Reason: {}", object, bucket, e.getMessage(), e);
-		    throw new DlabException(String.format("Cannot download object %s from bucket %s. Reason: %s", object, bucket, e.getMessage()));
-	    }
-        log.info("Finished downloading file {} from bucket {}", object, bucket);
-    }
-
-    @Override
-    public void deleteObjects(String bucket, List<String> objects) {
-	    try (S3Client s3 = S3Client.create()) {
-		    List<ObjectIdentifier> objectsToDelete = objects
-				    .stream()
-				    .map(o -> ObjectIdentifier.builder()
-						    .key(o)
-						    .build())
-				    .collect(Collectors.toList());
-
-		    DeleteObjectsRequest deleteObjectsRequests = DeleteObjectsRequest.builder()
-				    .bucket(bucket)
-				    .delete(Delete.builder()
-                            .objects(objectsToDelete)
-                            .build())
-                    .build();
-
-            s3.deleteObjects(deleteObjectsRequests);
-        } catch (Exception e) {
-		    log.error("Cannot delete objects {} from bucket {}. Reason: {}", objects, bucket, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot delete objects %s from bucket %s. Reason: %s", objects, bucket, e.getMessage()));
-        }
-    }
-
-    private BucketDTO toBucketDTO(String bucket, S3Object s3Object) {
-        Date date = Date.from(s3Object.lastModified());
-        SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
-        return BucketDTO.builder()
-                .bucket(bucket)
-                .object(s3Object.key())
-                .size(String.valueOf(s3Object.size()))
-                .lastModifiedDate(formatter.format(date))
-                .build();
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/azure/BucketServiceAzureImpl.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/azure/BucketServiceAzureImpl.java
deleted file mode 100644
index 073aca2..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/azure/BucketServiceAzureImpl.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * 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.azure;
-
-import com.azure.identity.ClientSecretCredentialBuilder;
-import com.azure.storage.blob.BlobClient;
-import com.azure.storage.blob.BlobContainerClient;
-import com.azure.storage.blob.BlobServiceClient;
-import com.azure.storage.blob.BlobServiceClientBuilder;
-import com.azure.storage.blob.models.BlobItem;
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.service.BucketService;
-import com.epam.dlab.dto.bucket.BucketDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.model.azure.AzureAuthFile;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.inject.Inject;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletResponse;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.time.format.DateTimeFormatter;
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Slf4j
-public class BucketServiceAzureImpl implements BucketService {
-    private final AzureAuthFile azureAuthFile;
-
-    @Inject
-    public BucketServiceAzureImpl(ProvisioningServiceApplicationConfiguration configuration) throws Exception {
-        azureAuthFile = getAzureAuthFile(configuration);
-    }
-
-    @Override
-    public List<BucketDTO> getObjects(String bucket) {
-        try {
-            AzureStorageAccount account = getAzureStorageAccount(bucket);
-            BlobServiceClient blobServiceClient = getBlobServiceClient(account.getStorageAccount());
-            BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient(account.getContainer());
-            return blobContainerClient.listBlobs()
-                    .stream()
-                    .map(blob -> toBucketDTO(account.getContainer(), blob))
-                    .collect(Collectors.toList());
-        } catch (Exception e) {
-            log.error("Cannot retrieve objects from bucket {}. Reason: {}", bucket, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot retrieve objects from bucket %s. Reason: %s", bucket, e.getMessage()));
-        }
-    }
-
-    @Override
-    public void uploadObject(String bucket, String object, InputStream stream, String contentType, long fileSize) {
-        log.info("Uploading file {} to bucket {}", object, bucket);
-        try {
-            AzureStorageAccount account = getAzureStorageAccount(bucket);
-            BlobServiceClient blobServiceClient = getBlobServiceClient(account.getStorageAccount());
-            BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient(account.getContainer());
-            BlobClient blobClient = blobContainerClient.getBlobClient(object);
-            blobClient.upload(stream, fileSize);
-        } catch (Exception e) {
-	        log.error("Cannot upload object {} to bucket {}. Reason: {}", object, bucket, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot upload object %s to bucket %s. Reason: %s", object, bucket, e.getMessage()));
-        }
-        log.info("Finished uploading file {} to bucket {}", object, bucket);
-    }
-
-    @Override
-    public void uploadFolder(UserInfo userInfo, String bucket, String folder) {
-        // Azure doesn't support this feature
-    }
-
-    @Override
-    public void downloadObject(String bucket, String object, HttpServletResponse resp) {
-        log.info("Downloading file {} from bucket {}", object, bucket);
-        try (ServletOutputStream outputStream = resp.getOutputStream()) {
-            AzureStorageAccount account = getAzureStorageAccount(bucket);
-            BlobServiceClient blobServiceClient = getBlobServiceClient(account.getStorageAccount());
-            BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient(account.getContainer());
-            BlobClient blobClient = blobContainerClient.getBlobClient(object);
-            blobClient.download(outputStream);
-        } catch (Exception e) {
-	        log.error("Cannot download object {} from bucket {}. Reason: {}", object, bucket, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot download object %s from bucket %s. Reason: %s", object, bucket, e.getMessage()));
-        }
-        log.info("Finished downloading file {} from bucket {}", object, bucket);
-    }
-
-    @Override
-    public void deleteObjects(String bucket, List<String> objects) {
-        try {
-            AzureStorageAccount account = getAzureStorageAccount(bucket);
-            BlobServiceClient blobServiceClient = getBlobServiceClient(account.getStorageAccount());
-            BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient(account.getContainer());
-            objects.forEach(object -> blobContainerClient.getBlobClient(object).delete());
-        } catch (Exception e) {
-	        log.error("Cannot delete objects {} from bucket {}. Reason: {}", objects, bucket, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot delete objects %s from bucket %s. Reason: %s", objects, bucket, e.getMessage()));
-        }
-    }
-
-    private BucketDTO toBucketDTO(String bucket, BlobItem blob) {
-        String lastModifiedDate = blob.getProperties().getLastModified().format(DateTimeFormatter.ofPattern(DATE_FORMAT));
-        return BucketDTO.builder()
-                .bucket(bucket)
-                .object(blob.getName())
-                .lastModifiedDate(lastModifiedDate)
-                .size(String.valueOf(blob.getProperties().getContentLength()))
-                .build();
-    }
-
-    private AzureAuthFile getAzureAuthFile(ProvisioningServiceApplicationConfiguration configuration) throws Exception {
-        final String authFile = configuration.getCloudConfiguration().getAzureAuthFile();
-        Path path = Paths.get(authFile);
-        if (path.toFile().exists()) {
-            try {
-                return new ObjectMapper().readValue(path.toFile(), AzureAuthFile.class);
-            } catch (IOException e) {
-                log.error("Cannot parse azure auth file {}", authFile, e);
-                throw new IOException("Cannot parse azure auth file " + authFile);
-            } catch (Exception e) {
-                log.error("Something went wrong while parsing azure auth file {}", authFile, e);
-                throw new Exception("Something went wrong while parsing azure auth file " + authFile);
-            }
-        } else {
-            throw new FileNotFoundException("Cannot find azure auth file for path" + authFile);
-        }
-    }
-
-    private BlobServiceClient getBlobServiceClient(String storageAccount) {
-        final String endpoint = String.format("https://%s.blob.core.windows.net", storageAccount);
-        return new BlobServiceClientBuilder()
-                .endpoint(endpoint)
-                .credential(new ClientSecretCredentialBuilder()
-                        .clientId(azureAuthFile.getClientId())
-                        .clientSecret(azureAuthFile.getClientSecret())
-                        .tenantId(azureAuthFile.getTenantId())
-                        .build())
-                .buildClient();
-    }
-
-    private AzureStorageAccount getAzureStorageAccount(String bucket) {
-        String[] a = bucket.split("\\.");
-        return new AzureStorageAccount(a[0], a[1]);
-    }
-
-    @Getter
-    @AllArgsConstructor
-    private static class AzureStorageAccount {
-        private final String storageAccount;
-        private final String container;
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/gcp/BucketServiceGcpImpl.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/gcp/BucketServiceGcpImpl.java
deleted file mode 100644
index 4a28bf6..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/gcp/BucketServiceGcpImpl.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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.gcp;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.BucketService;
-import com.epam.dlab.dto.bucket.BucketDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.google.cloud.storage.Blob;
-import com.google.cloud.storage.BlobId;
-import com.google.cloud.storage.BlobInfo;
-import com.google.cloud.storage.Bucket;
-import com.google.cloud.storage.Storage;
-import com.google.cloud.storage.StorageOptions;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletResponse;
-import java.io.InputStream;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
-
-@Slf4j
-public class BucketServiceGcpImpl implements BucketService {
-
-    @Override
-    public List<BucketDTO> getObjects(String bucket) {
-        try {
-            Storage storage = StorageOptions.getDefaultInstance().getService();
-            Bucket gcpBucket = storage.get(bucket);
-            return StreamSupport.stream(gcpBucket.list().getValues().spliterator(), false)
-                    .map(this::toBucketDTO)
-                    .collect(Collectors.toList());
-        } catch (Exception e) {
-            log.error("Cannot retrieve objects from bucket {}. Reason: {}", bucket, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot retrieve objects from bucket %s. Reason: %s", bucket, e.getMessage()));
-        }
-    }
-
-    @Override
-    public void uploadObject(String bucket, String object, InputStream stream, String contentType, long fileSize) {
-        log.info("Uploading file {} to bucket {}", object, bucket);
-        try {
-            Storage storage = StorageOptions.getDefaultInstance().getService();
-            BlobId blobId = BlobId.of(bucket, object);
-            BlobInfo blobInfo = BlobInfo.newBuilder(blobId)
-                    .setContentType(contentType)
-                    .build();
-            storage.create(blobInfo, stream);
-        } catch (Exception e) {
-	        log.error("Cannot upload object {} to bucket {}. Reason: {}", object, bucket, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot upload object %s to bucket %s. Reason: %s", object, bucket, e.getMessage()));
-        }
-        log.info("Finished uploading file {} to bucket {}", object, bucket);
-    }
-
-    @Override
-    public void uploadFolder(UserInfo userInfo, String bucket, String folder) {
-        log.info("Uploading file {} to bucket {}", folder, bucket);
-        try {
-            Storage storage = StorageOptions.getDefaultInstance().getService();
-            BlobId blobId = BlobId.of(bucket, folder);
-            BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build();
-            storage.create(blobInfo);
-        } catch (Exception e) {
-	        log.error("Cannot upload folder {} to bucket {}. Reason: {}", folder, bucket, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot upload folder %s to bucket %s. Reason: %s", folder, bucket, e.getMessage()));
-        }
-        log.info("Finished uploading folder {} to bucket {}", folder, bucket);
-    }
-
-    @Override
-    public void downloadObject(String bucket, String object, HttpServletResponse resp) {
-        log.info("Downloading file {} from bucket {}", object, bucket);
-        try (ServletOutputStream outputStream = resp.getOutputStream()) {
-            Storage storage = StorageOptions.getDefaultInstance().getService();
-            Blob blob = storage.get(BlobId.of(bucket, object));
-            blob.downloadTo(outputStream);
-            log.info("Finished downloading file {} from bucket {}", object, bucket);
-        } catch (Exception e) {
-	        log.error("Cannot download object {} from bucket {}. Reason: {}", object, bucket, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot download object %s from bucket %s. Reason: %s", object, bucket, e.getMessage()));
-        }
-        log.info("Finished downloading file {} from bucket {}", object, bucket);
-    }
-
-    @Override
-    public void deleteObjects(String bucket, List<String> objects) {
-        try {
-            Storage storage = StorageOptions.getDefaultInstance().getService();
-            List<BlobId> blobIds = objects
-                    .stream()
-                    .map(o -> BlobId.of(bucket, o))
-                    .collect(Collectors.toList());
-            storage.delete(blobIds);
-        } catch (Exception e) {
-	        log.error("Cannot delete objects {} from bucket {}. Reason: {}", objects, bucket, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot delete objects %s from bucket %s. Reason: %s", objects, bucket, e.getMessage()));
-        }
-    }
-
-    private BucketDTO toBucketDTO(BlobInfo blobInfo) {
-        Date date = new Date(blobInfo.getUpdateTime());
-        SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
-        return BucketDTO.builder()
-                .bucket(blobInfo.getBucket())
-                .object(blobInfo.getName())
-                .size(String.valueOf(blobInfo.getSize()))
-                .lastModifiedDate(formatter.format(date))
-                .build();
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/validation/ProvisioningServiceCloudConfigurationSequenceProvider.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/validation/ProvisioningServiceCloudConfigurationSequenceProvider.java
deleted file mode 100644
index b85af8a..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/validation/ProvisioningServiceCloudConfigurationSequenceProvider.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.validation;
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.validation.CloudConfigurationSequenceProvider;
-
-public class ProvisioningServiceCloudConfigurationSequenceProvider
-        extends CloudConfigurationSequenceProvider<ProvisioningServiceApplicationConfiguration> {
-
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/process/ProcessConveyor.java b/services/provisioning-service/src/main/java/com/epam/dlab/process/ProcessConveyor.java
deleted file mode 100644
index c2dbf37..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/process/ProcessConveyor.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.process;
-
-import com.aegisql.conveyor.AssemblingConveyor;
-import com.aegisql.conveyor.BuildingSite;
-import com.aegisql.conveyor.cart.Cart;
-import com.aegisql.conveyor.cart.FutureCart;
-import com.epam.dlab.process.model.ProcessId;
-import com.epam.dlab.process.model.ProcessInfo;
-import com.epam.dlab.process.model.ProcessStep;
-
-import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
-
-public class ProcessConveyor extends AssemblingConveyor<ProcessId, ProcessStep, ProcessInfo> {
-
-	public ProcessConveyor() {
-		super();
-		this.setName("ProcessConveyor");
-		this.setIdleHeartBeat(1, TimeUnit.SECONDS);
-		this.enablePostponeExpiration(true);
-		this.enablePostponeExpirationOnTimeout(true);
-		this.setDefaultCartConsumer((l, v, b) -> {
-			LOG.warn("default processor for {} {} {}", l, v, b.get());
-			if (v instanceof FutureCart) {
-				@SuppressWarnings("rawtypes")
-				FutureCart fc = (FutureCart) v;
-				fc.get().cancel(true);
-			}
-		});
-		this.setResultConsumer(bin -> LOG.debug("process finished: {}", bin));
-	}
-
-	public Supplier<? extends ProcessInfo> getInfoSupplier(ProcessId id) {
-		BuildingSite<ProcessId, ProcessStep, Cart<ProcessId, ?, ProcessStep>, ? extends ProcessInfo> bs = this.collector.get(id);
-		if (bs == null) {
-			return () -> null;
-		} else {
-			return bs.getProductSupplier();
-		}
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/process/builder/ProcessInfoBuilder.java b/services/provisioning-service/src/main/java/com/epam/dlab/process/builder/ProcessInfoBuilder.java
deleted file mode 100644
index 769bb05..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/process/builder/ProcessInfoBuilder.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * 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.process.builder;
-
-import com.aegisql.conveyor.Expireable;
-import com.aegisql.conveyor.Testing;
-import com.aegisql.conveyor.TimeoutAction;
-import com.epam.dlab.process.model.DlabProcess;
-import com.epam.dlab.process.model.ProcessId;
-import com.epam.dlab.process.model.ProcessInfo;
-import com.epam.dlab.process.model.ProcessStatus;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.reflect.Field;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.concurrent.CompletableFuture;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-import static com.epam.dlab.process.model.ProcessStatus.CREATED;
-import static com.epam.dlab.process.model.ProcessStatus.FAILED;
-import static com.epam.dlab.process.model.ProcessStatus.FINISHED;
-import static com.epam.dlab.process.model.ProcessStatus.KILLED;
-import static com.epam.dlab.process.model.ProcessStatus.LAUNCHING;
-import static com.epam.dlab.process.model.ProcessStatus.REJECTED;
-import static com.epam.dlab.process.model.ProcessStatus.RUNNING;
-import static com.epam.dlab.process.model.ProcessStatus.SCHEDULED;
-import static com.epam.dlab.process.model.ProcessStatus.STOPPED;
-import static com.epam.dlab.process.model.ProcessStatus.TIMEOUT;
-
-@Slf4j
-public class ProcessInfoBuilder implements Supplier<ProcessInfo>, Testing, TimeoutAction, Expireable {
-
-	private static Function<Process, Integer> pidSupplier = null;
-	private final ProcessId processId;
-	private final long startTimeStamp = System.currentTimeMillis();
-	private final StringBuilder stdOut = new StringBuilder();
-	private final StringBuilder stdErr = new StringBuilder();
-	private ProcessStatus status = CREATED;
-	private int exitCode = -1;
-	private String[] command = new String[]{"N/A"};
-	private Collection<ProcessInfo> rejected = null;
-	private int pid = -1;
-	private boolean finished = false;
-	private boolean stdOutClosed = false;
-	private boolean stdErrClosed = false;
-	private Process p = null;
-	private CompletableFuture<ProcessInfo> future;
-	private long expirationTime;
-
-	public ProcessInfoBuilder(ProcessId processId, long ttl) {
-		this.processId = processId;
-		this.expirationTime = System.currentTimeMillis() + ttl;
-	}
-
-	public static void schedule(ProcessInfoBuilder b, String[] command) {
-		b.status = SCHEDULED;
-		b.command = command;
-	}
-
-	public static void start(ProcessInfoBuilder b, String[] command) {
-		if (b.status == CREATED) {
-			b.status = LAUNCHING;
-			b.command = command;
-			b.launch();
-		} else {
-			if (b.rejected == null) {
-				b.rejected = new LinkedList<>();
-			}
-			long timeStamp = System.currentTimeMillis();
-			b.rejected.add(new ProcessInfo(
-					b.processId,
-					REJECTED,
-					command,
-					"",
-					"rejected duplicated command",
-					REJECTED.ordinal(),
-					timeStamp,
-					timeStamp, null, b.pid));
-		}
-	}
-
-	public static void failed(ProcessInfoBuilder b, Object dummy) {
-		b.status = FAILED;
-		b.setReady();
-	}
-
-	public static void stop(ProcessInfoBuilder b, Object dummy) {
-		if (b.p != null) {
-			b.p.destroy();
-		}
-		if (b.status != LAUNCHING && b.status != RUNNING) {
-			b.setReady();
-		}
-		b.status = STOPPED;
-	}
-
-	public static void kill(ProcessInfoBuilder b, Object dummy) {
-		if (b.p != null) {
-			b.p.destroyForcibly();
-		}
-		if (b.status != LAUNCHING && b.status != RUNNING) {
-			b.setReady();
-		}
-		b.status = KILLED;
-	}
-
-	public static void finish(ProcessInfoBuilder b, Integer exitCode) {
-		if (b.status != STOPPED && b.status != KILLED && b.status != TIMEOUT) {
-			b.status = FINISHED;
-		}
-		b.exitCode = exitCode;
-		b.finished = true;
-	}
-
-	public static void stdOut(ProcessInfoBuilder b, Object msg) {
-		if (msg == null) {
-			b.stdOutClosed = true;
-		} else {
-			b.stdOut.append(msg).append("\n");
-		}
-	}
-
-	public static void stdErr(ProcessInfoBuilder b, Object msg) {
-		if (msg == null) {
-			b.stdErrClosed = true;
-		} else {
-			b.stdErr.append(msg).append("\n");
-		}
-	}
-
-	public static void future(ProcessInfoBuilder b, CompletableFuture<ProcessInfo> future) {
-		if (b.future == null) {
-			b.future = future;
-		} else {
-			future.cancel(true);
-		}
-	}
-
-	public static int getPid(Process process) {
-		try {
-			if (pidSupplier == null) {
-				Class<?> cProcessImpl = process.getClass();
-				final Field fPid = cProcessImpl.getDeclaredField("pid");
-				log.debug("PID field found");
-				if (!fPid.isAccessible()) {
-					fPid.setAccessible(true);
-				}
-				pidSupplier = p -> {
-					try {
-						return fPid.getInt(p);
-					} catch (IllegalAccessException e) {
-						log.error("Unable to access PID. {}", e.getMessage(), e);
-						return -1;
-					}
-				};
-			}
-			return pidSupplier.apply(process);
-		} catch (NoSuchFieldException e) {
-			log.debug("PID field not found", e);
-			pidSupplier = p -> -1;
-			return -1;
-		}
-	}
-
-	private void launch() {
-		DlabProcess.getInstance().getUsersExecutorService(processId.getUser()).submit(() -> {
-			status = SCHEDULED;
-			DlabProcess.getInstance().getExecutorService().execute(() -> {
-				try {
-					p = new ProcessBuilder(command).start();
-					pid = getPid(p);
-					InputStream stdOutStream = p.getInputStream();
-					DlabProcess.getInstance().getExecutorService().execute(() -> print(stdOutStream));
-					InputStream stdErrStream = p.getErrorStream();
-					DlabProcess.getInstance().getExecutorService().execute(() -> printError(stdErrStream));
-					status = RUNNING;
-					int exit = p.waitFor();
-					DlabProcess.getInstance().finish(processId, exit);
-				} catch (IOException e) {
-					DlabProcess.getInstance().toStdErr(processId, "Command launch failed. " + get().getCommand(), e);
-					DlabProcess.getInstance().failed(processId);
-				} catch (InterruptedException e) {
-					DlabProcess.getInstance().toStdErr(processId, "Command interrupted. " + get().getCommand(), e);
-					DlabProcess.getInstance().failed(processId);
-					Thread.currentThread().interrupt();
-				}
-			});
-			try {
-				future.get();
-			} catch (Exception e) {
-				log.error("Exception occurred during getting future result: {}", e.getMessage(), e);
-			}
-		});
-	}
-
-	private void printError(InputStream stdErrStream) {
-		BufferedReader reader = new BufferedReader(new InputStreamReader(stdErrStream));
-		String line;
-		try {
-			while ((line = reader.readLine()) != null) {
-				DlabProcess.getInstance().toStdErr(processId, line);
-			}
-			DlabProcess.getInstance().toStdErr(processId, null);
-		} catch (IOException e) {
-			DlabProcess.getInstance().toStdErr(processId, "Failed process STDERR reader", e);
-			DlabProcess.getInstance().failed(processId);
-		}
-	}
-
-	private void print(InputStream stdOutStream) {
-		BufferedReader reader = new BufferedReader(new InputStreamReader(stdOutStream));
-		String line;
-		try {
-			while ((line = reader.readLine()) != null) {
-				DlabProcess.getInstance().toStdOut(processId, line);
-			}
-			DlabProcess.getInstance().toStdOut(processId, null);
-		} catch (IOException e) {
-			DlabProcess.getInstance().toStdErr(processId, "Failed process STDOUT reader", e);
-			DlabProcess.getInstance().failed(processId);
-		}
-	}
-
-	@Override
-	public ProcessInfo get() {
-		return new ProcessInfo(
-				processId,
-				status,
-				command,
-				stdOut.toString(),
-				stdErr.toString(),
-				exitCode,
-				startTimeStamp, System.currentTimeMillis(), rejected, pid);
-	}
-
-	@Override
-	public boolean test() {
-		return finished && stdOutClosed && stdErrClosed;
-	}
-
-	private void setReady() {
-		finished = true;
-		stdOutClosed = true;
-		stdErrClosed = true;
-	}
-
-	@Override
-	public void onTimeout() {
-		if (status != TIMEOUT) {
-			log.debug("Stopping on timeout ...");
-			stop(this, "STOP");
-			status = TIMEOUT;
-			expirationTime += 60_000;
-		} else {
-			log.debug("Killing on timeout ...");
-			kill(this, "KILL");
-			status = TIMEOUT;
-			setReady();
-		}
-	}
-
-	@Override
-	public long getExpirationTime() {
-		return expirationTime;
-	}
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/process/exception/DlabProcessException.java b/services/provisioning-service/src/main/java/com/epam/dlab/process/exception/DlabProcessException.java
deleted file mode 100644
index a7acc68..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/process/exception/DlabProcessException.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.process.exception;
-
-public class DlabProcessException extends RuntimeException {
-	private static final long serialVersionUID = 1L;
-
-	public DlabProcessException() {
-    }
-
-    public DlabProcessException(String message) {
-        super(message);
-    }
-
-    public DlabProcessException(String message, Exception cause) {
-        super(message, cause);
-    }
-
-    public DlabProcessException(Exception cause) {
-        super(cause);
-    }
-
-    public DlabProcessException(String message, Exception cause, boolean enableSuppression, boolean writableStackTrace) {
-        super(message, cause, enableSuppression, writableStackTrace);
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/process/model/DlabProcess.java b/services/provisioning-service/src/main/java/com/epam/dlab/process/model/DlabProcess.java
deleted file mode 100644
index e1bf636..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/process/model/DlabProcess.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * 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.process.model;
-
-import com.epam.dlab.process.ProcessConveyor;
-import com.epam.dlab.process.builder.ProcessInfoBuilder;
-import com.epam.dlab.util.SecurityUtils;
-import io.dropwizard.util.Duration;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-@Slf4j
-public class DlabProcess {
-
-	private final static DlabProcess INSTANCE = new DlabProcess();
-	private final ProcessConveyor processConveyor;
-	private ExecutorService executorService = Executors.newFixedThreadPool(50 * 3);
-	private Map<String, ExecutorService> perUserService = new ConcurrentHashMap<>();
-	private int userMaxparallelism = 5;
-	private long expirationTime = TimeUnit.HOURS.toMillis(3);
-
-	private DlabProcess() {
-		this.processConveyor = new ProcessConveyor();
-	}
-
-	public static DlabProcess getInstance() {
-		return INSTANCE;
-	}
-
-	public ExecutorService getExecutorService() {
-		return executorService;
-	}
-
-	public void setMaxProcessesPerBox(int parallelism) {
-		this.executorService.shutdown();
-		this.executorService = Executors.newFixedThreadPool(3 * parallelism);
-	}
-
-	public void setMaxProcessesPerUser(int parallelism) {
-		this.userMaxparallelism = parallelism;
-		this.perUserService.forEach((k, e) -> e.shutdown());
-		this.perUserService = new ConcurrentHashMap<>();
-	}
-
-	public ExecutorService getUsersExecutorService(String user) {
-		perUserService.putIfAbsent(user, Executors.newFixedThreadPool(userMaxparallelism));
-		return perUserService.get(user);
-	}
-
-	public CompletableFuture<ProcessInfo> start(ProcessId id, String... command) {
-		log.debug("Run OS command for user {} with UUID {}: {}", id.getUser(), id.getCommand(),
-				SecurityUtils.hideCreds(command));
-		CompletableFuture<ProcessInfo> future = processConveyor.createBuildFuture(id, () -> new ProcessInfoBuilder(id,
-				expirationTime));
-		processConveyor.add(id, future, ProcessStep.FUTURE);
-		processConveyor.add(id, command, ProcessStep.START);
-		return future;
-	}
-
-	public CompletableFuture<ProcessInfo> start(String username, String uniqDescriptor, String... command) {
-		return start(new ProcessId(username, uniqDescriptor), command);
-	}
-
-	public CompletableFuture<ProcessInfo> start(String username, String... command) {
-		return start(new ProcessId(username, String.join(" ", command)), command);
-	}
-
-
-	public CompletableFuture<Boolean> stop(ProcessId id) {
-		return processConveyor.add(id, "STOP", ProcessStep.STOP);
-	}
-
-	public CompletableFuture<Boolean> stop(String username, String command) {
-		return stop(new ProcessId(username, command));
-	}
-
-	public CompletableFuture<Boolean> kill(ProcessId id) {
-		return processConveyor.add(id, "KILL", ProcessStep.KILL);
-	}
-
-	public CompletableFuture<Boolean> kill(String username, String command) {
-		return kill(new ProcessId(username, command));
-	}
-
-	public CompletableFuture<Boolean> failed(ProcessId id) {
-		return processConveyor.add(id, "FAILED", ProcessStep.FAILED);
-	}
-
-	public CompletableFuture<Boolean> finish(ProcessId id, Integer exitStatus) {
-		return processConveyor.add(id, exitStatus, ProcessStep.FINISH);
-	}
-
-	public CompletableFuture<Boolean> toStdOut(ProcessId id, String msg) {
-		return processConveyor.add(id, msg, ProcessStep.STD_OUT);
-	}
-
-	public CompletableFuture<Boolean> toStdErr(ProcessId id, String msg) {
-		return processConveyor.add(id, msg, ProcessStep.STD_ERR);
-	}
-
-	public CompletableFuture<Boolean> toStdErr(ProcessId id, String msg, Exception err) {
-		StringWriter sw = new StringWriter();
-		sw.append(msg);
-		sw.append("\n");
-		PrintWriter pw = new PrintWriter(sw);
-		err.printStackTrace(pw);
-		return processConveyor.add(id, sw.toString(), ProcessStep.STD_ERR);
-	}
-
-	public Collection<ProcessId> getActiveProcesses() {
-		Collection<ProcessId> pList = new ArrayList<>();
-		processConveyor.forEachKeyAndBuilder((k, b) -> pList.add(k));
-		return pList;
-	}
-
-	public Collection<ProcessId> getActiveProcesses(String username) {
-		return getActiveProcesses()
-				.stream()
-				.filter(id -> id.getUser().equals(username))
-				.collect(Collectors.toList());
-	}
-
-	public Supplier<? extends ProcessInfo> getProcessInfoSupplier(ProcessId id) {
-		return processConveyor.getInfoSupplier(id);
-	}
-
-	public Supplier<? extends ProcessInfo> getProcessInfoSupplier(String username, String command) {
-		return getProcessInfoSupplier(new ProcessId(username, command));
-	}
-
-	public void setProcessTimeout(long time, TimeUnit unit) {
-		this.expirationTime = unit.toMillis(time);
-	}
-
-	public void setProcessTimeout(Duration duration) {
-		this.expirationTime = duration.toMilliseconds();
-	}
-
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/process/model/ProcessId.java b/services/provisioning-service/src/main/java/com/epam/dlab/process/model/ProcessId.java
deleted file mode 100644
index 69f01b5..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/process/model/ProcessId.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.process.model;
-
-public class ProcessId {
-
-    private final String user;
-    private final String command;
-
-    public ProcessId(String user, String command) {
-        this.user = user;
-        this.command = command;
-    }
-
-    public String getCommand() {
-        return command;
-    }
-
-    public String getUser() {
-        return user;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-	    if (this == o) {
-		    return true;
-	    }
-	    if (o == null || getClass() != o.getClass()) {
-		    return false;
-	    }
-
-	    ProcessId processId = (ProcessId) o;
-
-	    if (user != null ? !user.equals(processId.user) : processId.user != null) {
-		    return false;
-	    }
-	    return command != null ? command.equals(processId.command) : processId.command == null;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = user != null ? user.hashCode() : 0;
-        result = 31 * result + (command != null ? command.hashCode() : 0);
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "ProcessId{" +
-                "user='" + user + '\'' +
-                ", command='" + command + '\'' +
-                '}';
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/process/model/ProcessInfo.java b/services/provisioning-service/src/main/java/com/epam/dlab/process/model/ProcessInfo.java
deleted file mode 100644
index 629fd0d..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/process/model/ProcessInfo.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.process.model;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-
-public class ProcessInfo {
-
-    private final ProcessId id;
-    private final String[] command;
-    private final ProcessStatus status;
-    private final String stdOut;
-    private final String stdErr;
-    private final int exitCode;
-    private final long startTimeStamp;
-    private final long infoTimeStamp;
-    private final int pid;
-
-    private final Collection<ProcessInfo> rejectedCommands;
-
-    public ProcessInfo(ProcessId id, ProcessStatus status, String[] command, String stdOut, String stdErr, int exitCode,
-                 long startTimeStamp, long infoTimeStamp, Collection<ProcessInfo> rejected, int pid) {
-        this.id             = id;
-        this.status         = status;
-        this.command        = command;
-        this.stdOut         = stdOut;
-        this.stdErr         = stdErr;
-        this.exitCode       = exitCode;
-        this.startTimeStamp = startTimeStamp;
-        this.infoTimeStamp  = infoTimeStamp;
-        this.pid            = pid;
-
-        if(rejected != null && rejected.size() > 0) {
-            Collection<ProcessInfo> r = new ArrayList<>();
-            for(ProcessInfo info:rejected) {
-                if(info != null) {
-                    r.add(info);
-                }
-            }
-            this.rejectedCommands = Collections.unmodifiableCollection(r);
-        } else {
-            this.rejectedCommands = null;
-        }
-
-    }
-
-    public String getCommand() {
-        return String.join(" ",command);
-    }
-
-    public ProcessStatus getStatus() {
-        return status;
-    }
-
-    public String getStdOut() {
-        return stdOut;
-    }
-
-    public String getStdErr() {
-        return stdErr;
-    }
-
-    public int getExitCode() {
-        return exitCode;
-    }
-
-    public long getStartTimeStamp() {
-        return startTimeStamp;
-    }
-
-    public long getInfoTimeStamp() {
-        return infoTimeStamp;
-    }
-
-    public ProcessId getId() {
-        return id;
-    }
-
-    public int getPid() {
-        return pid;
-    }
-
-    public Collection<ProcessInfo> getRejectedCommands() {
-        return Collections.unmodifiableCollection(rejectedCommands);
-    }
-
-    @Override
-    public String toString() {
-        return "ProcessInfo{" +
-                "id='" + id + '\'' +
-                ", command='" + getCommand() + '\'' +
-                ", pid=" + pid +
-                ", status=" + status +
-                ", stdOut='" + stdOut + '\'' +
-                ", stdErr='" + stdErr + '\'' +
-                ", exitCode=" + exitCode +
-                ", startTimeStamp=" + startTimeStamp +
-                ", infoTimeStamp=" + infoTimeStamp +
-                ", rejectedCommands=" + rejectedCommands +
-                '}';
-    }
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/process/model/ProcessStatus.java b/services/provisioning-service/src/main/java/com/epam/dlab/process/model/ProcessStatus.java
deleted file mode 100644
index 35985b5..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/process/model/ProcessStatus.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.process.model;
-
-public enum ProcessStatus {
-    CREATED,
-    LAUNCHING,
-    RUNNING,
-    STOPPED,
-    KILLED,
-    TIMEOUT,
-    FINISHED,
-    REJECTED,
-    FAILED,
-    SCHEDULED
-}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/process/model/ProcessStep.java b/services/provisioning-service/src/main/java/com/epam/dlab/process/model/ProcessStep.java
deleted file mode 100644
index d45d5b6..0000000
--- a/services/provisioning-service/src/main/java/com/epam/dlab/process/model/ProcessStep.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.process.model;
-
-import com.aegisql.conveyor.SmartLabel;
-import com.epam.dlab.process.builder.ProcessInfoBuilder;
-
-import java.util.function.BiConsumer;
-
-public enum ProcessStep implements SmartLabel<ProcessInfoBuilder> {
-    START(ProcessInfoBuilder::start),
-    STOP(ProcessInfoBuilder::stop),
-    KILL(ProcessInfoBuilder::kill),
-    FINISH(ProcessInfoBuilder::finish),
-    STD_OUT(ProcessInfoBuilder::stdOut),
-    STD_ERR(ProcessInfoBuilder::stdErr),
-    FAILED(ProcessInfoBuilder::failed),
-    FUTURE(ProcessInfoBuilder::future),
-;
-    private BiConsumer<ProcessInfoBuilder, Object> consumer;
-
-    @SuppressWarnings("unchecked")
-	<T> ProcessStep(BiConsumer<ProcessInfoBuilder, T> consumer) {
-        this.consumer = (BiConsumer<ProcessInfoBuilder, Object>) consumer;
-    }
-
-    @Override
-    public BiConsumer<ProcessInfoBuilder, Object> get() {
-        return consumer;
-    }
-}
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/backup.json b/services/provisioning-service/src/main/resources/mock_response/aws/backup.json
index 53e9f40..0b81c3a 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/backup.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/backup.json
@@ -1,5 +1,5 @@
 {
   "status": "created",
-  "backup_file": "/opt/dlab/tmp/dlab.tar.gz",
+  "backup_file": "/opt/datalab/tmp/datalab.tar.gz",
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_configure.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_configure.json
index b8be3bf..6219072 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_configure.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_configure.json
@@ -6,7 +6,7 @@
          "Tag_name": "${CONF_SERVICE_BASE_NAME}-tag",
          "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
       },
-      "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_configure_failed.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_configure_failed.json
index a33e4b4..6dbbf5b 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_configure_failed.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_configure_failed.json
@@ -5,7 +5,7 @@
       "hostname": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-des-${EXPLORATORY_NAME}-${COMPUTATIONAL_NAME}-${NOTEBOOK_ID}",
       "error": "Cannot configure EMR"
     },
-    "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_create.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_create.json
index b3b8d8d..d532992 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_create.json
@@ -14,7 +14,7 @@
           }
         ]
       },
-      "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_create_failed.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_create_failed.json
index 96093ef..beb8aa2 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_create_failed.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_create_failed.json
@@ -5,7 +5,7 @@
       "hostname": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-des-${EXPLORATORY_NAME}-${COMPUTATIONAL_NAME}-${NOTEBOOK_ID}",
       "error":"Cannot create EMR"
     },
-    "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_lib_install.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_lib_install.json
index 4110cf8..29bb856 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_lib_install.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_lib_install.json
@@ -5,7 +5,7 @@
       "Action": "Install additional libs",
       "Libs": ${LIB_INSTALL}
 },
-"log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+"log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
 },
 "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_lib_list.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_lib_list.json
index 2fba799..92348cf 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_lib_list.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_lib_list.json
@@ -3,9 +3,9 @@
   "response": {
     "result": {
       "Action": "Get list of all available libraries",
-      "file": "/opt/dlab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
+      "file": "/opt/datalab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_terminate.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_terminate.json
index 4864cc1..a8fbad1 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine-service_terminate.json
@@ -7,7 +7,7 @@
          "EMR_name": "${EMR_CLUSTER_NAME}",
          "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
       },
-      "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_configure.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_configure.json
index 6529169..685ba64 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_configure.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_configure.json
@@ -5,7 +5,7 @@
       "Action": "Configure notebook server",
       "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_create.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_create.json
index 9df4d36..9c19f00 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_create.json
@@ -16,7 +16,7 @@
         }
       ]
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_lib_install.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_lib_install.json
index 4110cf8..29bb856 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_lib_install.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_lib_install.json
@@ -5,7 +5,7 @@
       "Action": "Install additional libs",
       "Libs": ${LIB_INSTALL}
 },
-"log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+"log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
 },
 "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_lib_list.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_lib_list.json
index 2fba799..92348cf 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_lib_list.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_lib_list.json
@@ -3,9 +3,9 @@
   "response": {
     "result": {
       "Action": "Get list of all available libraries",
-      "file": "/opt/dlab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
+      "file": "/opt/datalab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_start.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_start.json
index fe559d9..110fbb6 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_start.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_start.json
@@ -5,7 +5,7 @@
       "Action": "Start Data Engine",
       "service_base_name": "${CONF_SERVICE_BASE_NAME}"
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_stop.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_stop.json
index 44da2d2..5396ad5 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_stop.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_stop.json
@@ -5,7 +5,7 @@
       "Action": "Stop Data Engine",
       "service_base_name": "${CONF_SERVICE_BASE_NAME}"
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_terminate.json b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_terminate.json
index 6fb7768..d3b2135 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/dataengine_terminate.json
@@ -5,7 +5,7 @@
       "Action": "Terminate Data Engine",
       "service_base_name": "${CONF_SERVICE_BASE_NAME}"
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/edge_create.json b/services/provisioning-service/src/main/resources/mock_response/aws/edge_create.json
index 81afe8a..abf75c3 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/edge_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/edge_create.json
@@ -32,10 +32,10 @@
       "edge_sg": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-SG",
       "socks_port": "1080",
       "notebook_subnet": "172.31.48.0/24",
-      "@class": "com.epam.dlab.dto.aws.edge.EdgeInfoAws",
+      "@class": "com.epam.datalab.dto.aws.edge.EdgeInfoAws",
       "shared_bucket_name": "${CONF_SERVICE_BASE_NAME}-shared-bucket"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/edge_start.json b/services/provisioning-service/src/main/resources/mock_response/aws/edge_start.json
index 5dca2f0..3cee1bb 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/edge_start.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/edge_start.json
@@ -8,7 +8,7 @@
          "Action": "Start up notebook server",
          "ip": "172.31.2.250"
       },
-      "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/edge_stop.json b/services/provisioning-service/src/main/resources/mock_response/aws/edge_stop.json
index 1a5d4df..dd0ea45 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/edge_stop.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/edge_stop.json
@@ -5,7 +5,7 @@
          "instance_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge",
          "Action": "Stop edge server"
       },
-      "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/edge_terminate.json b/services/provisioning-service/src/main/resources/mock_response/aws/edge_terminate.json
index 5de66ef..b303484 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/edge_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/edge_terminate.json
@@ -6,7 +6,7 @@
       "service_base_name": "${CONF_SERVICE_BASE_NAME}",
       "user_name": "${EDGE_USER_NAME}"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_check_inactivity.json b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_check_inactivity.json
index af3320b..0fdcd05 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_check_inactivity.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_check_inactivity.json
@@ -2,7 +2,7 @@
   "status": "ok",
   "response": {
     "result": "1549464798",
-    "log": "/var/log/dlab/notebook/notebook_bohdan_hliva_eb30e2bb-28db-4b07-bf16-e634d448952f.log"
+    "log": "/var/log/datalab/notebook/notebook_bohdan_hliva_eb30e2bb-28db-4b07-bf16-e634d448952f.log"
   },
   "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create.json b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create.json
index 53193b4..794eeba 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create.json
@@ -15,7 +15,7 @@
          "Action": "Create new notebook server",
          "master_keyname": "${CONF_KEY_NAME}"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create_failed.json b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create_failed.json
index 156c73d..a5e663f 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create_failed.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create_failed.json
@@ -5,7 +5,7 @@
       "error": " [Error-2017-07-12 13:08:51]:Failed to configure TensorFlow.",
       "notebook_name" : "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-nb-${EXPLORATORY_NAME}-${NOTEBOOK_ID}"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create_image.json b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create_image.json
index 939b7d6..3538ddf 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create_image.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create_image.json
@@ -10,7 +10,7 @@
          "status" : "created",
          "Action": "Create image from notebook"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_git_creds.json b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_git_creds.json
index a2b2650..8820278 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_git_creds.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_git_creds.json
@@ -4,7 +4,7 @@
       "result": {
          "Action": "Setup git credentials"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_lib_install.json b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_lib_install.json
index fa90f10..4992831 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_lib_install.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_lib_install.json
@@ -5,7 +5,7 @@
       "Action": "Install additional libs",
       "Libs": ${LIB_INSTALL}
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
-  },
-  "request_id": "${REQUEST_ID}"
+"log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+},
+"request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_lib_list.json b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_lib_list.json
index 2fba799..92348cf 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_lib_list.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_lib_list.json
@@ -3,9 +3,9 @@
   "response": {
     "result": {
       "Action": "Get list of all available libraries",
-      "file": "/opt/dlab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
+      "file": "/opt/datalab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_start.json b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_start.json
index 525bd9a..6fa8fe8 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_start.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_start.json
@@ -8,7 +8,7 @@
          "hostname": "ip-172-31-48-131.us-west-2.compute.internal",
          "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_status.json b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_status.json
index 940a137..7ecad18 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_status.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_status.json
@@ -1,8 +1,10 @@
 {
-   "status": "ok",
-   "response": {
-      "result": ${LIST_RESOURCES},
-      "log": "/var/log/dlab/status/status_${EDGE_USER_NAME}_${REQUEST_ID}.log"
-   },
-   "request_id": "${REQUEST_ID}"
+  "status": "ok",
+  "response": {
+    "result": ${
+  LIST_RESOURCES
+},
+"log": "/var/log/datalab/status/status_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+},
+"request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_stop.json b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_stop.json
index e0ee8b1..fd77b99 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_stop.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_stop.json
@@ -7,7 +7,7 @@
          "Tag_name": "${CONF_SERVICE_BASE_NAME}-tag",
          "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_terminate.json b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_terminate.json
index a9e2a3a..9db74c9 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_terminate.json
@@ -7,7 +7,7 @@
          "Tag_name": "${CONF_SERVICE_BASE_NAME}-tag",
          "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/project_create.json b/services/provisioning-service/src/main/resources/mock_response/aws/project_create.json
index d5f2d68..e63315f 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/project_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/project_create.json
@@ -6,7 +6,7 @@
       "full_edge_conf": {
         "edge_service_account_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge",
         "fw_edge_egress_internal": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-egress-internal",
-        "dlab_ssh_user": "dlab-user",
+        "datalab_ssh_user": "datalab-user",
         "ps_role_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps",
         "fw_ps_egress_public": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps-egress-public",
         "private_ip": "10.10.0.3",
@@ -36,7 +36,7 @@
         "edge_user_name": "${EDGE_USER_NAME}",
         "private_subnet_cidr": "10.10.16.0/24",
         "fw_edge_ingress_internal": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-ingress-internal",
-        "vpc_selflink": "https://www.googleapis.com/compute/v1/projects/or2-msq-epmc-dlab-t1iylu/global/networks/${CONF_SERVICE_BASE_NAME}-ssn-vpc",
+        "vpc_selflink": "https://www.googleapis.com/compute/v1/projects/or2-msq-epmc-datalab-t1iylu/global/networks/${CONF_SERVICE_BASE_NAME}-ssn-vpc",
         "instance_size": "n1-standard-1",
         "notebook_firewall_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-nb-firewall"
       },
@@ -49,9 +49,9 @@
       "socks_port": "1080",
       "notebook_subnet": "10.10.16.0/24",
       "project_name": "${PROJECT_NAME}",
-      "@class": "com.epam.dlab.dto.aws.edge.EdgeInfoAws"
+      "@class": "com.epam.datalab.dto.aws.edge.EdgeInfoAws"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/project_terminate.json b/services/provisioning-service/src/main/resources/mock_response/aws/project_terminate.json
index 5de66ef..b303484 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/project_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/project_terminate.json
@@ -6,7 +6,7 @@
       "service_base_name": "${CONF_SERVICE_BASE_NAME}",
       "user_name": "${EDGE_USER_NAME}"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/backup.json b/services/provisioning-service/src/main/resources/mock_response/azure/backup.json
index 53e9f40..0b81c3a 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/backup.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/backup.json
@@ -1,5 +1,5 @@
 {
   "status": "created",
-  "backup_file": "/opt/dlab/tmp/dlab.tar.gz",
+  "backup_file": "/opt/datalab/tmp/datalab.tar.gz",
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_configure.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_configure.json
index b8be3bf..6219072 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_configure.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_configure.json
@@ -6,7 +6,7 @@
          "Tag_name": "${CONF_SERVICE_BASE_NAME}-tag",
          "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
       },
-      "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_configure_failed.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_configure_failed.json
index a33e4b4..6dbbf5b 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_configure_failed.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_configure_failed.json
@@ -5,7 +5,7 @@
       "hostname": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-des-${EXPLORATORY_NAME}-${COMPUTATIONAL_NAME}-${NOTEBOOK_ID}",
       "error": "Cannot configure EMR"
     },
-    "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_create.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_create.json
index 05bc93a..48e8049 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_create.json
@@ -14,7 +14,7 @@
           }
         ]
       },
-      "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_create_failed.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_create_failed.json
index 96093ef..beb8aa2 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_create_failed.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_create_failed.json
@@ -5,7 +5,7 @@
       "hostname": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-des-${EXPLORATORY_NAME}-${COMPUTATIONAL_NAME}-${NOTEBOOK_ID}",
       "error":"Cannot create EMR"
     },
-    "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_lib_install.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_lib_install.json
index 4110cf8..29bb856 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_lib_install.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_lib_install.json
@@ -5,7 +5,7 @@
       "Action": "Install additional libs",
       "Libs": ${LIB_INSTALL}
 },
-"log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+"log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
 },
 "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_lib_list.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_lib_list.json
index 2fba799..92348cf 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_lib_list.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_lib_list.json
@@ -3,9 +3,9 @@
   "response": {
     "result": {
       "Action": "Get list of all available libraries",
-      "file": "/opt/dlab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
+      "file": "/opt/datalab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_terminate.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_terminate.json
index 4864cc1..a8fbad1 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine-service_terminate.json
@@ -7,7 +7,7 @@
          "EMR_name": "${EMR_CLUSTER_NAME}",
          "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
       },
-      "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_configure.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_configure.json
index 6529169..685ba64 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_configure.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_configure.json
@@ -5,7 +5,7 @@
       "Action": "Configure notebook server",
       "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_create.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_create.json
index 9df4d36..9c19f00 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_create.json
@@ -16,7 +16,7 @@
         }
       ]
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_lib_install.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_lib_install.json
index 4110cf8..29bb856 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_lib_install.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_lib_install.json
@@ -5,7 +5,7 @@
       "Action": "Install additional libs",
       "Libs": ${LIB_INSTALL}
 },
-"log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+"log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
 },
 "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_lib_list.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_lib_list.json
index 2fba799..92348cf 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_lib_list.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_lib_list.json
@@ -3,9 +3,9 @@
   "response": {
     "result": {
       "Action": "Get list of all available libraries",
-      "file": "/opt/dlab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
+      "file": "/opt/datalab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_start.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_start.json
index fe559d9..110fbb6 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_start.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_start.json
@@ -5,7 +5,7 @@
       "Action": "Start Data Engine",
       "service_base_name": "${CONF_SERVICE_BASE_NAME}"
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_stop.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_stop.json
index 44da2d2..5396ad5 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_stop.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_stop.json
@@ -5,7 +5,7 @@
       "Action": "Stop Data Engine",
       "service_base_name": "${CONF_SERVICE_BASE_NAME}"
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_terminate.json b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_terminate.json
index 6fb7768..d3b2135 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/dataengine_terminate.json
@@ -5,7 +5,7 @@
       "Action": "Terminate Data Engine",
       "service_base_name": "${CONF_SERVICE_BASE_NAME}"
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/edge_create.json b/services/provisioning-service/src/main/resources/mock_response/azure/edge_create.json
index b2a9931..975ab6a 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/edge_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/edge_create.json
@@ -34,7 +34,7 @@
          "notebook_subnet": "172.31.48.0/24",
          "shared_bucket_name": "${CONF_SERVICE_BASE_NAME}-shared-bucket"
       },
-      "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/edge_start.json b/services/provisioning-service/src/main/resources/mock_response/azure/edge_start.json
index 5dca2f0..3cee1bb 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/edge_start.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/edge_start.json
@@ -8,7 +8,7 @@
          "Action": "Start up notebook server",
          "ip": "172.31.2.250"
       },
-      "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/edge_stop.json b/services/provisioning-service/src/main/resources/mock_response/azure/edge_stop.json
index 1a5d4df..dd0ea45 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/edge_stop.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/edge_stop.json
@@ -5,7 +5,7 @@
          "instance_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge",
          "Action": "Stop edge server"
       },
-      "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/edge_terminate.json b/services/provisioning-service/src/main/resources/mock_response/azure/edge_terminate.json
index 5de66ef..b303484 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/edge_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/edge_terminate.json
@@ -6,7 +6,7 @@
       "service_base_name": "${CONF_SERVICE_BASE_NAME}",
       "user_name": "${EDGE_USER_NAME}"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create.json b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create.json
index 53193b4..794eeba 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create.json
@@ -15,7 +15,7 @@
          "Action": "Create new notebook server",
          "master_keyname": "${CONF_KEY_NAME}"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create_failed.json b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create_failed.json
index 156c73d..a5e663f 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create_failed.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create_failed.json
@@ -5,7 +5,7 @@
       "error": " [Error-2017-07-12 13:08:51]:Failed to configure TensorFlow.",
       "notebook_name" : "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-nb-${EXPLORATORY_NAME}-${NOTEBOOK_ID}"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create_image.json b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create_image.json
index 2ea6023..b34972d 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create_image.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create_image.json
@@ -11,7 +11,7 @@
          "ip" : "102.011.10.3",
          "Action": "Create image from notebook"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_git_creds.json b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_git_creds.json
index a2b2650..8820278 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_git_creds.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_git_creds.json
@@ -4,7 +4,7 @@
       "result": {
          "Action": "Setup git credentials"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_lib_install.json b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_lib_install.json
index fa90f10..4992831 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_lib_install.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_lib_install.json
@@ -5,7 +5,7 @@
       "Action": "Install additional libs",
       "Libs": ${LIB_INSTALL}
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
-  },
-  "request_id": "${REQUEST_ID}"
+"log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+},
+"request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_lib_list.json b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_lib_list.json
index 2fba799..92348cf 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_lib_list.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_lib_list.json
@@ -3,9 +3,9 @@
   "response": {
     "result": {
       "Action": "Get list of all available libraries",
-      "file": "/opt/dlab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
+      "file": "/opt/datalab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_start.json b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_start.json
index 525bd9a..6fa8fe8 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_start.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_start.json
@@ -8,7 +8,7 @@
          "hostname": "ip-172-31-48-131.us-west-2.compute.internal",
          "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_status.json b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_status.json
index 940a137..7ecad18 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_status.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_status.json
@@ -1,8 +1,10 @@
 {
-   "status": "ok",
-   "response": {
-      "result": ${LIST_RESOURCES},
-      "log": "/var/log/dlab/status/status_${EDGE_USER_NAME}_${REQUEST_ID}.log"
-   },
-   "request_id": "${REQUEST_ID}"
+  "status": "ok",
+  "response": {
+    "result": ${
+  LIST_RESOURCES
+},
+"log": "/var/log/datalab/status/status_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+},
+"request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_stop.json b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_stop.json
index e0ee8b1..fd77b99 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_stop.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_stop.json
@@ -7,7 +7,7 @@
          "Tag_name": "${CONF_SERVICE_BASE_NAME}-tag",
          "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_terminate.json b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_terminate.json
index a9e2a3a..9db74c9 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_terminate.json
@@ -7,7 +7,7 @@
          "Tag_name": "${CONF_SERVICE_BASE_NAME}-tag",
          "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/project_create.json b/services/provisioning-service/src/main/resources/mock_response/azure/project_create.json
index 41a6692..79a1cc5 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/project_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/project_create.json
@@ -6,7 +6,7 @@
       "full_edge_conf": {
         "edge_service_account_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge",
         "fw_edge_egress_internal": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-egress-internal",
-        "dlab_ssh_user": "dlab-user",
+        "datalab_ssh_user": "datalab-user",
         "ps_role_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps",
         "fw_ps_egress_public": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps-egress-public",
         "private_ip": "10.10.0.3",
@@ -36,7 +36,7 @@
         "edge_user_name": "${EDGE_USER_NAME}",
         "private_subnet_cidr": "10.10.16.0/24",
         "fw_edge_ingress_internal": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-ingress-internal",
-        "vpc_selflink": "https://www.googleapis.com/compute/v1/projects/or2-msq-epmc-dlab-t1iylu/global/networks/${CONF_SERVICE_BASE_NAME}-ssn-vpc",
+        "vpc_selflink": "https://www.googleapis.com/compute/v1/projects/or2-msq-epmc-datalab-t1iylu/global/networks/${CONF_SERVICE_BASE_NAME}-ssn-vpc",
         "instance_size": "n1-standard-1",
         "notebook_firewall_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-nb-firewall"
       },
@@ -49,9 +49,9 @@
       "socks_port": "1080",
       "notebook_subnet": "10.10.16.0/24",
       "project_name": "${PROJECT_NAME}",
-      "@class": "com.epam.dlab.dto.azure.edge.EdgeInfoAzure"
+      "@class": "com.epam.datalab.dto.azure.edge.EdgeInfoAzure"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/project_terminate.json b/services/provisioning-service/src/main/resources/mock_response/azure/project_terminate.json
index 5de66ef..b303484 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/project_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/project_terminate.json
@@ -6,7 +6,7 @@
       "service_base_name": "${CONF_SERVICE_BASE_NAME}",
       "user_name": "${EDGE_USER_NAME}"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/backup.json b/services/provisioning-service/src/main/resources/mock_response/gcp/backup.json
index 53e9f40..0b81c3a 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/backup.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/backup.json
@@ -1,5 +1,5 @@
 {
   "status": "created",
-  "backup_file": "/opt/dlab/tmp/dlab.tar.gz",
+  "backup_file": "/opt/datalab/tmp/datalab.tar.gz",
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_configure.json b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_configure.json
index b8be3bf..6219072 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_configure.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_configure.json
@@ -6,7 +6,7 @@
          "Tag_name": "${CONF_SERVICE_BASE_NAME}-tag",
          "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
       },
-      "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_create.json b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_create.json
index a0a3635..46b1ff0 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_create.json
@@ -14,7 +14,7 @@
           }
         ]
       },
-      "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_lib_install.json b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_lib_install.json
index 4110cf8..29bb856 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_lib_install.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_lib_install.json
@@ -5,7 +5,7 @@
       "Action": "Install additional libs",
       "Libs": ${LIB_INSTALL}
 },
-"log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+"log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
 },
 "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_lib_list.json b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_lib_list.json
index 2fba799..92348cf 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_lib_list.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_lib_list.json
@@ -3,9 +3,9 @@
   "response": {
     "result": {
       "Action": "Get list of all available libraries",
-      "file": "/opt/dlab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
+      "file": "/opt/datalab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_terminate.json b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_terminate.json
index e7bb257..e90242d 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine-service_terminate.json
@@ -7,7 +7,7 @@
          "Dataproc_name": "${DATAPROC_CLUSTER_NAME}",
          "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
       },
-      "log": "/var/log/dlab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/emr/emr_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_configure.json b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_configure.json
index 6529169..685ba64 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_configure.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_configure.json
@@ -5,7 +5,7 @@
       "Action": "Configure notebook server",
       "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_create.json b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_create.json
index d6398fe..4ffd543 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_create.json
@@ -13,7 +13,7 @@
         }
       ]
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_lib_install.json b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_lib_install.json
index 4110cf8..29bb856 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_lib_install.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_lib_install.json
@@ -5,7 +5,7 @@
       "Action": "Install additional libs",
       "Libs": ${LIB_INSTALL}
 },
-"log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+"log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
 },
 "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_lib_list.json b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_lib_list.json
index 2fba799..92348cf 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_lib_list.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_lib_list.json
@@ -3,9 +3,9 @@
   "response": {
     "result": {
       "Action": "Get list of all available libraries",
-      "file": "/opt/dlab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
+      "file": "/opt/datalab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_start.json b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_start.json
index fe559d9..110fbb6 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_start.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_start.json
@@ -5,7 +5,7 @@
       "Action": "Start Data Engine",
       "service_base_name": "${CONF_SERVICE_BASE_NAME}"
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_stop.json b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_stop.json
index 44da2d2..5396ad5 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_stop.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_stop.json
@@ -5,7 +5,7 @@
       "Action": "Stop Data Engine",
       "service_base_name": "${CONF_SERVICE_BASE_NAME}"
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_terminate.json b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_terminate.json
index 6fb7768..d3b2135 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/dataengine_terminate.json
@@ -5,7 +5,7 @@
       "Action": "Terminate Data Engine",
       "service_base_name": "${CONF_SERVICE_BASE_NAME}"
     },
-    "log": "/var/log/dlab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/dataengine/dataengine_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/edge_create.json b/services/provisioning-service/src/main/resources/mock_response/gcp/edge_create.json
index e0cd288..fc4ba51 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/edge_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/edge_create.json
@@ -6,7 +6,7 @@
       "full_edge_conf": {
         "edge_service_account_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge",
         "fw_edge_egress_internal": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-egress-internal",
-        "dlab_ssh_user": "dlab-user",
+        "datalab_ssh_user": "datalab-user",
         "ps_role_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps",
         "fw_ps_egress_public": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps-egress-public",
         "private_ip": "10.10.0.3",
@@ -36,7 +36,7 @@
         "edge_user_name": "${EDGE_USER_NAME}",
         "private_subnet_cidr": "10.10.16.0/24",
         "fw_edge_ingress_internal": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-ingress-internal",
-        "vpc_selflink": "https://www.googleapis.com/compute/v1/projects/or2-msq-epmc-dlab-t1iylu/global/networks/${CONF_SERVICE_BASE_NAME}-ssn-vpc",
+        "vpc_selflink": "https://www.googleapis.com/compute/v1/projects/or2-msq-epmc-datalab-t1iylu/global/networks/${CONF_SERVICE_BASE_NAME}-ssn-vpc",
         "instance_size": "n1-standard-1",
         "notebook_firewall_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-nb-firewall"
       },
@@ -49,7 +49,7 @@
       "socks_port": "1080",
       "notebook_subnet": "10.10.16.0/24"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/edge_start.json b/services/provisioning-service/src/main/resources/mock_response/gcp/edge_start.json
index 2954c00..476faaf 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/edge_start.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/edge_start.json
@@ -8,7 +8,7 @@
       "Action": "Start up notebook server",
       "ip": "10.10.0.3"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/edge_stop.json b/services/provisioning-service/src/main/resources/mock_response/gcp/edge_stop.json
index a631927..e2ce9cb 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/edge_stop.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/edge_stop.json
@@ -5,7 +5,7 @@
       "instance_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge",
       "Action": "Stop edge server"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/edge_terminate.json b/services/provisioning-service/src/main/resources/mock_response/gcp/edge_terminate.json
index 5de66ef..b303484 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/edge_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/edge_terminate.json
@@ -6,7 +6,7 @@
       "service_base_name": "${CONF_SERVICE_BASE_NAME}",
       "user_name": "${EDGE_USER_NAME}"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create.json b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create.json
index 7d7bad5..7583e59 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create.json
@@ -19,7 +19,7 @@
       "Action": "Create new notebook server",
       "master_keyname": "${CONF_KEY_NAME}"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create_image.json b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create_image.json
index 344bb51..d1a5d34 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create_image.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create_image.json
@@ -11,7 +11,7 @@
          "ip": "102.011.10.3",
          "Action": "Create image from notebook"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_git_creds.json b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_git_creds.json
index a2b2650..8820278 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_git_creds.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_git_creds.json
@@ -4,7 +4,7 @@
       "result": {
          "Action": "Setup git credentials"
       },
-      "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+      "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
    },
    "request_id": "${REQUEST_ID}"
 }
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_lib_install.json b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_lib_install.json
index fa90f10..4992831 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_lib_install.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_lib_install.json
@@ -5,7 +5,7 @@
       "Action": "Install additional libs",
       "Libs": ${LIB_INSTALL}
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
-  },
-  "request_id": "${REQUEST_ID}"
+"log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+},
+"request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_lib_list.json b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_lib_list.json
index 2fba799..92348cf 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_lib_list.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_lib_list.json
@@ -3,9 +3,9 @@
   "response": {
     "result": {
       "Action": "Get list of all available libraries",
-      "file": "/opt/dlab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
+      "file": "/opt/datalab/tmp/result/notebook_${REQUEST_ID}_all_pkgs.json"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_start.json b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_start.json
index 1833413..0643bbc 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_start.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_start.json
@@ -7,7 +7,7 @@
       "hostname": "10.10.16.2",
       "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_status.json b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_status.json
index 940a137..7ecad18 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_status.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_status.json
@@ -1,8 +1,10 @@
 {
-   "status": "ok",
-   "response": {
-      "result": ${LIST_RESOURCES},
-      "log": "/var/log/dlab/status/status_${EDGE_USER_NAME}_${REQUEST_ID}.log"
-   },
-   "request_id": "${REQUEST_ID}"
+  "status": "ok",
+  "response": {
+    "result": ${
+  LIST_RESOURCES
+},
+"log": "/var/log/datalab/status/status_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+},
+"request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_stop.json b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_stop.json
index 016d23e..d1af1a2 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_stop.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_stop.json
@@ -5,7 +5,7 @@
       "Action": "Stop notebook server",
       "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
     },
-    "log": "/var/log/dlab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_terminate.json b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_terminate.json
index 989fc3d..82e0da4 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_terminate.json
@@ -5,7 +5,7 @@
       "Action": "Terminate notebook server",
       "notebook_name": "${NOTEBOOK_INSTANCE_NAME}"
     },
-    "log": "/var/log/dlab/notebook/notebook_{EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/notebook/notebook_{EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/project_create.json b/services/provisioning-service/src/main/resources/mock_response/gcp/project_create.json
index 31ca8e5..5b5c021 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/project_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/project_create.json
@@ -6,7 +6,7 @@
       "full_edge_conf": {
         "edge_service_account_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge",
         "fw_edge_egress_internal": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-egress-internal",
-        "dlab_ssh_user": "dlab-user",
+        "datalab_ssh_user": "datalab-user",
         "ps_role_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps",
         "fw_ps_egress_public": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps-egress-public",
         "private_ip": "10.10.0.3",
@@ -36,7 +36,7 @@
         "edge_user_name": "${EDGE_USER_NAME}",
         "private_subnet_cidr": "10.10.16.0/24",
         "fw_edge_ingress_internal": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-ingress-internal",
-        "vpc_selflink": "https://www.googleapis.com/compute/v1/projects/or2-msq-epmc-dlab-t1iylu/global/networks/${CONF_SERVICE_BASE_NAME}-ssn-vpc",
+        "vpc_selflink": "https://www.googleapis.com/compute/v1/projects/or2-msq-epmc-datalab-t1iylu/global/networks/${CONF_SERVICE_BASE_NAME}-ssn-vpc",
         "instance_size": "n1-standard-1",
         "notebook_firewall_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-nb-firewall"
       },
@@ -49,9 +49,9 @@
       "socks_port": "1080",
       "notebook_subnet": "10.10.16.0/24",
       "project_name": "${PROJECT_NAME}",
-      "@class": "com.epam.dlab.dto.gcp.edge.EdgeInfoGcp"
+      "@class": "com.epam.datalab.dto.gcp.edge.EdgeInfoGcp"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/project_terminate.json b/services/provisioning-service/src/main/resources/mock_response/gcp/project_terminate.json
index 7420ded..619dc39 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/project_terminate.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/project_terminate.json
@@ -6,7 +6,7 @@
       "project_tag": "prj1",
       "service_base_name": "${CONF_SERVICE_BASE_NAME}"
     },
-    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+    "log": "/var/log/datalab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
   },
   "request_id": "${REQUEST_ID}"
 }
\ No newline at end of file
diff --git a/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/DockerWarmuperTest.java b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/DockerWarmuperTest.java
new file mode 100644
index 0000000..285010b
--- /dev/null
+++ b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/DockerWarmuperTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.datalab.backendapi.core;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.commands.ICommandExecutor;
+import com.epam.datalab.backendapi.core.response.folderlistener.FolderListenerExecutor;
+import com.epam.datalab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
+import com.epam.datalab.dto.imagemetadata.ComputationalMetadataDTO;
+import com.epam.datalab.dto.imagemetadata.ComputationalResourceShapeDto;
+import com.epam.datalab.dto.imagemetadata.ExploratoryMetadataDTO;
+import com.epam.datalab.dto.imagemetadata.ImageMetadataDTO;
+import com.epam.datalab.dto.imagemetadata.ImageType;
+import com.epam.datalab.process.model.ProcessInfo;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import io.dropwizard.util.Duration;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DockerWarmuperTest {
+	@Inject
+	private DockerWarmuper warmuper;
+	private ExploratoryMetadataDTO exploratoryMetadata = new ExploratoryMetadataDTO(
+			"executeResult");
+	private ComputationalMetadataDTO computationalMetadata = new
+			ComputationalMetadataDTO("executeResult");
+	private static final String EXPLORATORY_TEST_JSON = "{\"exploratory_environment_shapes\" : { \"Category\" : [ " +
+			"{\"Size\":\"L\", \"Type\":\"cg1.4xlarge\",\"Ram\": \"22.5 GB\",\"Cpu\": \"16\"}]}}";
+	private static final String COMPUTATIONAL_TEST_JSON = "{\"template_name\":\"EMR cluster\"}";
+
+	@Before
+	public void setup() {
+		createInjector().injectMembers(this);
+		ComputationalResourceShapeDto computationalResourceShapeDto = new ComputationalResourceShapeDto();
+		computationalResourceShapeDto.setSize("L");
+		computationalResourceShapeDto.setType("cg1.4xlarge");
+		computationalResourceShapeDto.setRam("22.5 GB");
+		computationalResourceShapeDto.setCpu(16);
+		List<ComputationalResourceShapeDto> metadataArray = new ArrayList<>();
+		metadataArray.add(computationalResourceShapeDto);
+		HashMap<String, List<ComputationalResourceShapeDto>> map = new HashMap<>();
+		map.put("Category", metadataArray);
+		exploratoryMetadata.setExploratoryEnvironmentShapes(map);
+		computationalMetadata.setTemplateName("EMR cluster");
+	}
+
+	@Test
+	public void warmupSuccess() throws Exception {
+		warmuper.start();
+		warmuper.getFileHandlerCallback(getFirstUUID())
+				.handle(getFileName(), EXPLORATORY_TEST_JSON.getBytes());
+		warmuper.getFileHandlerCallback(getFirstUUID())
+				.handle(getFileName(), COMPUTATIONAL_TEST_JSON.getBytes());
+
+		ImageMetadataDTO testExploratory = warmuper.getMetadata(ImageType.EXPLORATORY)
+				.toArray(new ImageMetadataDTO[1])[0];
+		testExploratory.setImage("executeResult");
+		assertEquals(exploratoryMetadata.getImageType(), testExploratory.getImageType());
+
+		ImageMetadataDTO testComputational = warmuper.getMetadata(ImageType.COMPUTATIONAL)
+				.toArray(new ImageMetadataDTO[1])[0];
+		testComputational.setImage("executeResult");
+		assertEquals(computationalMetadata.getImageType(), testComputational.getImageType());
+	}
+
+	private String getFirstUUID() {
+		return warmuper.getUuids().keySet().toArray(new String[1])[0];
+	}
+
+	private String getFileName() {
+		return getFirstUUID() + ".json";
+	}
+
+	private Injector createInjector() {
+		return Guice.createInjector(new AbstractModule() {
+			@Override
+			protected void configure() {
+				bind(FolderListenerExecutor.class).toInstance(mock(FolderListenerExecutor.class));
+				bind(ProvisioningServiceApplicationConfiguration.class).toInstance(createConfiguration());
+				bind(ICommandExecutor.class).toInstance(createCommandExecutor());
+				bind(CallbackHandlerDao.class).toInstance(mock(CallbackHandlerDao.class));
+			}
+		});
+	}
+
+	private ProvisioningServiceApplicationConfiguration createConfiguration() {
+		ProvisioningServiceApplicationConfiguration result = mock(ProvisioningServiceApplicationConfiguration.class);
+		when(result.getWarmupDirectory()).thenReturn("/tmp");
+		when(result.getWarmupPollTimeout()).thenReturn(Duration.seconds(3));
+		return result;
+	}
+
+	private ICommandExecutor createCommandExecutor() {
+		ICommandExecutor result = mock(ICommandExecutor.class);
+		try {
+			final ProcessInfo pi = mock(ProcessInfo.class);
+			when(pi.getStdOut()).thenReturn("executeResult");
+			when(result.executeSync(anyString(), anyString(), anyString())).thenReturn(pi);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return result;
+	}
+}
diff --git a/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMockTest.java b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMockTest.java
new file mode 100644
index 0000000..3cb9d26
--- /dev/null
+++ b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMockTest.java
@@ -0,0 +1,398 @@
+/*
+ * 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.datalab.backendapi.core.commands;
+
+import com.epam.datalab.backendapi.core.response.handlers.ExploratoryCallbackHandler;
+import com.epam.datalab.backendapi.core.response.handlers.LibListCallbackHandler;
+import com.epam.datalab.backendapi.core.response.handlers.ResourceCallbackHandler;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.rest.client.RESTServiceMock;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
+
+@Ignore
+public class CommandExecutorMockTest {
+	private CommandExecutorMock getCommandExecutor() {
+		return new CommandExecutorMock(CloudProvider.AWS);
+	}
+
+	private CommandExecutorMock executeAsync(String cmd) throws IOException, InterruptedException, ExecutionException {
+		String uuid = UUID.randomUUID().toString();
+		CommandExecutorMock exec = new CommandExecutorMock(CloudProvider.AWS);
+		exec.executeAsync("user", uuid, cmd);
+		exec.getResultSync();
+
+		Files.deleteIfExists(Paths.get(exec.getResponseFileName()));
+
+		return exec;
+	}
+
+	private String getRequestId(CommandExecutorMock exec) {
+		return exec.getVariables().get("request_id");
+	}
+
+	private String getEdgeUserName(CommandExecutorMock exec) {
+		return exec.getVariables().get("edge_user_name");
+	}
+
+	private String getExploratoryName(CommandExecutorMock exec) {
+		return exec.getVariables().get("exploratory_name");
+	}
+
+	private void handleExploratory(String cmd, DockerAction action) throws Exception {
+		String uuid = UUID.randomUUID().toString();
+		CommandExecutorMock exec = getCommandExecutor();
+		exec.executeAsync("user", uuid, cmd);
+		exec.getResultSync();
+
+		RESTServiceMock selfService = new RESTServiceMock();
+		ExploratoryCallbackHandler handler = new ExploratoryCallbackHandler(selfService, action,
+				getRequestId(exec), getEdgeUserName(exec), "", getExploratoryName(exec));
+		handler.handle(exec.getResponseFileName(), Files.readAllBytes(Paths.get(exec.getResponseFileName())));
+
+		try {
+			Files.deleteIfExists(Paths.get(exec.getResponseFileName()));
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	private void handleExploratoryLibs(String cmd, DockerAction action) throws Exception {
+		String uuid = UUID.randomUUID().toString();
+		CommandExecutorMock exec = getCommandExecutor();
+		exec.executeAsync("user", uuid, cmd);
+		exec.getResultSync();
+
+		RESTServiceMock selfService = new RESTServiceMock();
+		if (action == DockerAction.LIB_INSTALL) {
+			throw new Exception("Unimplemented action " + action);
+		}
+		/*
+		ResourceCallbackHandler<?> handler = action.equals(DockerAction.LIB_INSTALL) ?
+				new LibInstallCallbackHandler(selfService, action,
+				getRequestId(exec), getEdgeUserName(exec), getExploratoryName(exec)):
+				new LibListCallbackHandler(selfService, action,
+				getRequestId(exec), getEdgeUserName(exec), getExploratoryName(exec));
+		*/
+		ResourceCallbackHandler<?> handler = new LibListCallbackHandler(selfService, action, getRequestId(exec),
+				getEdgeUserName(exec), getExploratoryName(exec));
+
+		handler.handle(exec.getResponseFileName(), Files.readAllBytes(Paths.get(exec.getResponseFileName())));
+
+		try {
+			Files.deleteIfExists(Paths.get(exec.getResponseFileName()));
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	@Test
+	public void describe() throws IOException, InterruptedException, ExecutionException {
+		String cmd =
+				"docker run " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/notebook:/logs/notebook " +
+						"-e \"conf_resource=notebook\" " +
+						"-e \"request_id=28ba67a4-b2ee-4753-a406-892977089ad9\" " +
+						"docker.datalab-zeppelin:latest --action describe";
+		executeAsync(cmd);
+	}
+
+	@Test
+	public void edgeCreate() throws IOException, InterruptedException, ExecutionException {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"," +
+						"\"conf_service_base_name\":\"usein1120v13\",\"conf_os_family\":\"debian\"," +
+						"\"aws_vpc_id\":\"vpc-83c469e4\",\"aws_subnet_id\":\"subnet-22db937a\"," +
+						"\"aws_security_groups_ids\":\"sg-4d42dc35\"}' | " +
+						"docker run -i --name user_create_edge_1487309918496 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/edge:/logs/edge " +
+						"-e \"conf_resource=edge\" " +
+						"-e \"request_id=b8267ae6-07b0-44ef-a489-7714b20cf0a4\" " +
+						"-e \"conf_key_name=BDCC-DSS-POC\" " +
+						"docker.datalab-edge --action create";
+		executeAsync(cmd);
+	}
+
+	@Test
+	public void edgeStop() throws IOException, InterruptedException, ExecutionException {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"," +
+						"\"conf_service_base_name\":\"usein1122v4\",\"conf_os_family\":\"debian\"}' | " +
+						"docker run -i --name user_stop_edge_1487677431773 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/edge:/logs/edge " +
+						"-e \"conf_resource=edge\" " +
+						"-e \"request_id=2ba3d8f7-654b-48aa-9386-e815b296a957\" " +
+						"-e \"conf_key_name=BDCC-DSS-POC\" " +
+						"docker.datalab-edge --action stop";
+		executeAsync(cmd);
+	}
+
+	@Test
+	public void edgeStart() throws IOException, InterruptedException, ExecutionException {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"," +
+						"\"conf_service_base_name\":\"usein1122v4\",\"conf_os_family\":\"debian\"}' | " +
+						"docker run -i --name user_start_edge_1487677538220 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/edge:/logs/edge " +
+						"-e \"conf_resource=edge\" " +
+						"-e \"request_id=d2f6fbae-979e-4b08-9c0d-559a103ec0cc\" " +
+						"-e \"conf_key_name=BDCC-DSS-POC\" " +
+						"docker.datalab-edge --action start";
+		executeAsync(cmd);
+	}
+
+	@Test
+	public void edgeStatus() throws IOException, InterruptedException, ExecutionException {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"," +
+						"\"edge_list_resources\":{\"host\":[{\"id\":\"i-05c1a0d0ad030cdc1\"}, " +
+						"{\"id\":\"i-05c1a0d0ad030cdc2\"}]}}' | " +
+						"docker run -i --name user_status_resources_1487607145484 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/edge:/logs/edge " +
+						"-e \"conf_resource=status\" " +
+						"-e \"request_id=0fb82e16-deb2-4b18-9ab3-f9f1c12d9e62\" " +
+						"-e \"conf_key_name=BDCC-DSS-POC\" " +
+						"docker.datalab-edge --action status";
+		executeAsync(cmd);
+	}
+
+
+	@Test
+	public void notebookCreate() throws Exception {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"," +
+						"\"conf_service_base_name\":\"usein1120v13\",\"conf_os_family\":\"debian\"," +
+						"\"exploratory_name\":\"useinxz1\",\"application\":\"zeppelin\",\"notebook_image\":\"docker" +
+						".datalab-zeppelin\"," +
+						"\"aws_notebook_instance_type\":\"t2.medium\",\"aws_security_groups_ids\":\"sg-4d42dc35\"}' " +
+						"|" +
+						" " +
+						"docker run -i --name user_create_exploratory_useinxz1_1487312574572 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/notebook:/logs/notebook " +
+						"-e \"conf_resource=notebook\" " +
+						"-e \"request_id=f720f30b-5949-4919-a50b-ce7af58d6fe9\" " +
+						"-e \"conf_key_name=BDCC-DSS-POC\" " +
+						"docker.datalab-zeppelin --action create";
+		handleExploratory(cmd, DockerAction.CREATE);
+	}
+
+	@Test
+	public void notebookStop() throws Exception {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"," +
+						"\"conf_service_base_name\":\"usein1120v13\"," +
+						"\"exploratory_name\":\"useinxz1\",\"notebook_image\":\"docker.datalab-zeppelin\"," +
+						"\"notebook_instance_name\":\"usein1120v13-user-nb-useinxz1-78af3\"," +
+						"\"conf_key_dir\":\"/root/keys\"}' | " +
+						"docker run -i --name user_stop_exploratory_useinxz1_1487315364165 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/notebook:/logs/notebook " +
+						"-e \"conf_resource=notebook\" " +
+						"-e \"request_id=33998e05-7781-432e-b748-bf3f0e7f9342\" " +
+						"-e \"conf_key_name=BDCC-DSS-POC\" " +
+						"docker.datalab-zeppelin --action stop";
+		handleExploratory(cmd, DockerAction.STOP);
+	}
+
+	@Test
+	public void notebookStart() throws Exception {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"," +
+						"\"conf_service_base_name\":\"usein1120v13\",\"conf_os_family\":\"debian\"," +
+						"\"exploratory_name\":\"useinxz1\",\"notebook_image\":\"docker.datalab-zeppelin\"," +
+						"\"notebook_instance_name\":\"usein1120v13-user-nb-useinxz1-78af3\"}' | " +
+						"docker run -i --name user_start_exploratory_useinxz1_1487316756857 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/notebook:/logs/notebook " +
+						"-e \"conf_resource=notebook\" " +
+						"-e \"request_id=d50b9d20-1b1a-415f-8e47-ed0aca029e73\" " +
+						"-e \"conf_key_name=BDCC-DSS-POC\" " +
+						"docker.datalab-zeppelin --action start";
+		handleExploratory(cmd, DockerAction.START);
+	}
+
+	@Test
+	public void notebookTerminate() throws Exception {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"," +
+						"\"conf_service_base_name\":\"usein1120v13\",\"conf_os_family\":\"debian\"," +
+						"\"exploratory_name\":\"useinxz1\",\"notebook_image\":\"docker.datalab-zeppelin\"," +
+						"\"notebook_instance_name\":\"usein1120v13-user-nb-useinxz1-78af3\"}' | " +
+						"docker run -i --name user_terminate_exploratory_useinxz1_1487318040180 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/notebook:/logs/notebook " +
+						"-e \"conf_resource=notebook\" " +
+						"-e \"request_id=de217441-9757-4c4e-b020-548f66b58e00\" " +
+						"-e \"conf_key_name=BDCC-DSS-POC\" " +
+						"docker.datalab-zeppelin --action terminate";
+		handleExploratory(cmd, DockerAction.TERMINATE);
+	}
+
+
+	@Test
+	public void emrCreate() throws Exception {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"," +
+						"\"conf_service_base_name\":\"usein1122v3\",\"conf_os_family\":\"debian\"," +
+						"\"exploratory_name\":\"useinj1\",\"application\":\"jupyter\"," +
+						"\"computational_name\":\"useine1\"," +
+						"\"emr_instance_count\":\"2\",\"emr_master_instance_type\":\"c4.large\"," +
+						"\"emr_slave_instance_type\":\"c4.large\"," +
+						"\"emr_version\":\"emr-5.2.0\",\"notebook_instance_name\":\"usein1122v3-user-nb-useinj1" +
+						"-1b198" +
+						"\"," +
+						"\"notebook_template_name\":\"Jupyter 1.5\"}' | " +
+						"docker run -i --name user_create_computational_useine1_1487653987822 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/emr:/logs/emr " +
+						"-e \"conf_resource=emr\" " +
+						"-e \"request_id=917db3fd-3c17-4e79-8462-482a71a5d96f\" " +
+						"-e \"ec2_role=EMR_EC2_DefaultRole\" " +
+						"-e \"emr_timeout=3600\" " +
+						"-e \"service_role=EMR_DefaultRole\" " +
+						"-e \"conf_key_name=BDCC-DSS-POC\" " +
+						"docker.datalab-emr --action create";
+		executeAsync(cmd);
+	}
+
+	@Test
+	public void emrConfigure() throws Exception {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"," +
+						"\"conf_service_base_name\":\"usein1122v4\",\"exploratory_name\":\"useinj1\"," +
+						"\"application\":\"jupyter\",\"computational_name\":\"useine2\",\"emr_version\":\"emr-5.2" +
+						".0\"," +
+						"\"notebook_instance_name\":\"usein1122v4-user-nb-useinj1-b0a2e\"}' | " +
+						"docker run -i --name user_configure_computational_useine2_1487676513703 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/emr:/logs/emr " +
+						"-e \"conf_resource=emr\" " +
+						"-e \"request_id=dc3c1002-c07d-442b-99f9-18085aeb2881\" " +
+						"-e \"conf_key_name=BDCC-DSS-POC\" " +
+						"docker.datalab-jupyter --action configure";
+		executeAsync(cmd);
+	}
+
+	@Test
+	public void emrTerminate() throws Exception {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"" +
+						",\"conf_service_base_name\":\"usein1122v3\",\"exploratory_name\":\"useinj1\"," +
+						"\"computational_name\":\"useine1\"," +
+						"\"emr_cluster_name\":\"usein1122v3-user-emr-useinj1-useine1-d2db9\"," +
+						"\"notebook_instance_name\":\"usein1122v3-user-nb-useinj1-1b198\"," +
+						"\"conf_key_dir\":\"/root/keys\"}' | " +
+						"docker run -i --name user_terminate_computational_useine1_1487657251858 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/emr:/logs/emr " +
+						"-e \"conf_resource=emr\" " +
+						"-e \"request_id=2d5c23b8-d312-4fad-8a3c-0b813550d841\" " +
+						"-e \"conf_key_name=BDCC-DSS-POC\" " +
+						"docker.datalab-emr --action terminate";
+		executeAsync(cmd);
+	}
+
+
+	@Test
+	public void listLibs() throws Exception {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"" +
+						",\"conf_service_base_name\":\"usein1122v3\",\"exploratory_name\":\"useinj1\"," +
+						"\"computational_name\":\"useine1\"," +
+						"\"emr_cluster_name\":\"usein1122v3-user-emr-useinj1-useine1-d2db9\"," +
+						"\"notebook_instance_name\":\"usein1122v3-user-nb-useinj1-1b198\"," +
+						"\"conf_key_dir\":\"/root/keys\"}' | " +
+						"docker run -i --name user_terminate_computational_useine1_1487657251858 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/emr:/logs/emr " +
+						"-e \"conf_resource=notebook\" " +
+						"-e \"request_id=2d5c23b8-d312-4fad-8a3c-0b813550d841\" " +
+						"-e \"conf_key_name=BDCC-DSS-POC\" " +
+						"-e \"application=jupyter\" " +
+						"docker.datalab-jupyter --action lib_list";
+		executeAsync(cmd);
+		handleExploratoryLibs(cmd, DockerAction.LIB_LIST);
+	}
+
+	@Test
+	public void installLibs() throws Exception {
+		String cmd =
+				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
+						"\"edge_user_name\":\"user\"" +
+						",\"conf_service_base_name\":\"usein1122v3\",\"exploratory_name\":\"useinj1\"," +
+						"\"computational_name\":\"useine1\"," +
+						"\"emr_cluster_name\":\"usein1122v3-user-emr-useinj1-useine1-d2db9\"," +
+						"\"notebook_instance_name\":\"usein1122v3-user-nb-useinj1-1b198\"," +
+						"\"conf_key_dir\":\"/root/keys\"}' | " +
+						"docker run -i --name user_terminate_computational_useine1_1487657251858 " +
+						"-v /home/ubuntu/keys:/root/keys " +
+						"-v /opt/datalab/tmp/result:/response " +
+						"-v /var/opt/datalab/log/emr:/logs/emr " +
+						"-e \"conf_resource=notebook\" " +
+						"-e \"additional_libs={'libraries': {\n" +
+						"\t\t\t\t'os_pkg': ['nmap', 'htop'],\n" +
+						"\t\t\t\t'pip2': ['requests', 'configparser'],\n" +
+						"\t\t\t\t'pip3': ['configparser'],\n" +
+						"\t\t\t\t'r_pkg': ['rmarkdown']\n" +
+						"\t\t\t\t}\n" +
+						"\t\t\t\t}\" " +
+						"docker.datalab-jupyter --action lib_install";
+		executeAsync(cmd);
+		handleExploratoryLibs(cmd, DockerAction.LIB_INSTALL);
+	}
+
+}
diff --git a/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/docker/command/ImagesDockerCommandTest.java b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/docker/command/ImagesDockerCommandTest.java
new file mode 100644
index 0000000..919daf6
--- /dev/null
+++ b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/docker/command/ImagesDockerCommandTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.backendapi.core.docker.command;
+
+import com.epam.datalab.backendapi.core.commands.ImagesDockerCommand;
+import com.epam.datalab.backendapi.core.commands.UnixCommand;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ImagesDockerCommandTest {
+
+    String GET_IMAGES = "docker images | awk '{print $1\":\"$2}' | sort | uniq | grep \"datalab\" | grep -v \"none\" | grep -v \"edge\"";
+
+    @Test
+    public void testBuildGetImagesCommand() {
+        String getImagesCommand = new ImagesDockerCommand()
+                .pipe(UnixCommand.awk("{print $1\":\"$2}"))
+                .pipe(UnixCommand.sort())
+                .pipe(UnixCommand.uniq())
+                .pipe(UnixCommand.grep("datalab"))
+                .pipe(UnixCommand.grep("none", "-v"))
+                .pipe(UnixCommand.grep("edge", "-v"))
+                .toCMD();
+        assertEquals(GET_IMAGES, getImagesCommand);
+    }
+}
diff --git a/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/docker/command/RunDockerCommandTest.java b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/docker/command/RunDockerCommandTest.java
new file mode 100644
index 0000000..05b3300
--- /dev/null
+++ b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/docker/command/RunDockerCommandTest.java
@@ -0,0 +1,319 @@
+/*
+ * 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.datalab.backendapi.core.docker.command;
+
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class RunDockerCommandTest {
+
+    String DOCKER_BASE = "docker run -v %s:/root/keys -v %s:/response -e \"request_id=%s\" ";
+
+    String GET_IMAGE_METADATA = DOCKER_BASE + "%s --action describe";
+
+    String RUN_IMAGE = DOCKER_BASE + "-e \"dry_run=true\" %s --action run";
+
+    String CREATE_EDGE_METADATA = DOCKER_BASE +
+            "-e \"conf_service_base_name=%s\" " +
+            "-e \"conf_key_name=%s\" " +
+            "-e \"edge_user_name=%s\" " +
+            "%s --action create";
+
+    String CREATE_EMR_CLUSTER = DOCKER_BASE +
+            "-e \"conf_service_base_name=%s\" " +
+            "-e \"emr_instance_count=%s\" " +
+            "-e \"emr_instance_type=%s\" " +
+            "-e \"emr_version=%s\" " +
+            "-e \"ec2_role=%s\" " +
+            "-e \"service_role=%s\" " +
+            "-e \"notebook_name=%s\" " +
+            "-e \"edge_user_name=%s\" " +
+            "-e \"edge_subnet_cidr=%s\" " +
+            "-e \"aws_region=%s\" " +
+            "-e \"conf_key_name=%s\" " +
+            "%s --action create";
+
+    String TERMINATE_EMR_CLUSTER = DOCKER_BASE +
+            "-e \"conf_service_base_name=%s\" " +
+            "-e \"edge_user_name=%s\" " +
+            "-e \"emr_cluster_name=%s\" " +
+            "-e \"aws_region=%s\" " +
+            "-e \"conf_key_name=%s\" " +
+            "%s --action terminate";
+
+    String EXPLORATORY_ENVIRONMENT = DOCKER_BASE +
+            "-e \"conf_service_base_name=%s\" " +
+            "-e \"aws_region=%s\" " +
+            "-e \"conf_key_name=%s\" ";
+
+    String CREATE_EXPLORATORY_ENVIRONMENT = EXPLORATORY_ENVIRONMENT +
+            "-e \"edge_user_name=%s\" " +
+            "-e \"notebook_subnet_cidr=%s\" " +
+            "-e \"aws_security_groups_ids=%s\" " +
+            "%s --action create";
+
+    String TERMINATE_EXPLORATORY_ENVIRONMENT = EXPLORATORY_ENVIRONMENT +
+            "-e \"edge_user_name=%s\" " +
+            "-e \"notebook_instance_name=%s\" " +
+            "%s --action terminate";
+
+    String STOP_EXPLORATORY_ENVIRONMENT = EXPLORATORY_ENVIRONMENT +
+            "-e \"edge_user_name=%s\" " +
+            "-e \"notebook_instance_name=%s\" " +
+            "%s --action stop";
+
+    String rootKeysVolume = "rkv";
+    String responseVolume = "rv";
+    String requestID = "rID";
+    String toDescribe = "tds";
+    String credsKeyName = "ckn";
+    String confServiceBaseName = "csbn";
+    String edgeUserName = "eun";
+    String userKeyName = "ukn";
+    String toCreate = "tc";
+    String toTerminate = "tt";
+    String toStop = "ts";
+    String toRun = "tr";
+    String emrInstanceCount = "10";
+    String emrInstanceType = "emit";
+    String emrVersion = "ev";
+    String ec2Role = "e2r";
+    String serviceRole = "sr";
+    String notebookName = "nn";
+    String edgeSubnetCidr = "esc";
+    String credsRegion = "cr";
+    String emrClusterName = "ecn";
+    String notebookUserName = "nun";
+    String notebookSubnetCidr = "nsc";
+    String credsSecurityGroupsIds = "csgi";
+    String notebookInstanceName = "nin";
+
+    @Test
+    public void testBuildDockerBaseCommand() {
+        RunDockerCommand dockerBaseCommand = new RunDockerCommand()
+                .withVolumeForRootKeys(rootKeysVolume)
+                .withVolumeForResponse(responseVolume)
+                .withRequestId(requestID);
+        assertEquals(String.format(DOCKER_BASE, rootKeysVolume, responseVolume, requestID), dockerBaseCommand.toCMD() + " ");
+    }
+
+    @Test
+    public void testBuildGetImageMetadataCommand() {
+        RunDockerCommand getImageMetadataCommand = new RunDockerCommand()
+                .withVolumeForRootKeys(rootKeysVolume)
+                .withVolumeForResponse(responseVolume)
+                .withRequestId(requestID)
+                .withActionDescribe(toDescribe);
+        assertEquals(String.format(GET_IMAGE_METADATA, rootKeysVolume, responseVolume, requestID, toDescribe), getImageMetadataCommand.toCMD());
+    }
+
+    @Test
+    public void testBuildCreateEdgeMetadataCommand() {
+        RunDockerCommand createEdgeMetadataCommand = new RunDockerCommand()
+                .withVolumeForRootKeys(rootKeysVolume)
+                .withVolumeForResponse(responseVolume)
+                .withRequestId(requestID)
+                .withConfServiceBaseName(confServiceBaseName)
+                .withConfKeyName(credsKeyName)
+                .withEdgeUserName(edgeUserName)
+                .withActionCreate(toCreate);
+        assertEquals(String.format(CREATE_EDGE_METADATA, rootKeysVolume, responseVolume,
+                requestID, confServiceBaseName, credsKeyName, edgeUserName, toCreate),
+                createEdgeMetadataCommand.toCMD());
+    }
+
+    @Test
+    public void testBuildRunImageCommand() {
+        RunDockerCommand runImageCommand = new RunDockerCommand()
+                .withVolumeForRootKeys(rootKeysVolume)
+                .withVolumeForResponse(responseVolume)
+                .withRequestId(requestID)
+                .withDryRun()
+                .withActionRun(toRun);
+        assertEquals(String.format(RUN_IMAGE, rootKeysVolume, responseVolume, requestID, toRun), runImageCommand.toCMD());
+    }
+
+    @Test
+    public void testCreateEMRClusterCommand() {
+        RunDockerCommand createEMRClusterCommand = new RunDockerCommand()
+                .withVolumeForRootKeys(rootKeysVolume)
+                .withVolumeForResponse(responseVolume)
+                .withRequestId(requestID)
+                .withConfServiceBaseName(confServiceBaseName)
+                .withEmrInstanceCount(emrInstanceCount)
+                .withEmrInstanceType(emrInstanceType)
+                .withEmrVersion(emrVersion)
+                .withEc2Role(ec2Role)
+                .withServiceRole(serviceRole)
+                .withNotebookName(notebookName)
+                .withEdgeUserName(edgeUserName)
+                .withEdgeSubnetCidr(edgeSubnetCidr)
+                .withAwsRegion(credsRegion)
+                .withConfKeyName(credsKeyName)
+                .withActionCreate(toCreate);
+
+        assertEquals(
+                String.format(
+                        CREATE_EMR_CLUSTER,
+                        rootKeysVolume,
+                        responseVolume,
+                        requestID,
+                        confServiceBaseName,
+                        emrInstanceCount,
+                        emrInstanceType,
+                        emrVersion,
+                        ec2Role,
+                        serviceRole,
+                        notebookName,
+                        edgeUserName,
+                        edgeSubnetCidr,
+                        credsRegion,
+                        credsKeyName,
+                        toCreate
+                ),
+                createEMRClusterCommand.toCMD()
+        );
+    }
+
+    @Test
+    public void testTerminateEmrCluster() {
+        RunDockerCommand terminateEMRClusterCommand = new RunDockerCommand()
+                .withVolumeForRootKeys(rootKeysVolume)
+                .withVolumeForResponse(responseVolume)
+                .withRequestId(requestID)
+                .withConfServiceBaseName(confServiceBaseName)
+                .withEdgeUserName(edgeUserName)
+                .withEmrClusterName(emrClusterName)
+                .withAwsRegion(credsRegion)
+                .withConfKeyName(credsKeyName)
+                .withActionTerminate(toTerminate);
+
+        assertEquals(
+                String.format(
+                        TERMINATE_EMR_CLUSTER,
+                        rootKeysVolume,
+                        responseVolume,
+                        requestID,
+                        confServiceBaseName,
+                        edgeUserName,
+                        emrClusterName,
+                        credsRegion,
+                        credsKeyName,
+                        toTerminate
+                ),
+                terminateEMRClusterCommand.toCMD()
+        );
+    }
+
+    @Test
+    public void testCreateExploratoryEnvironment() {
+        RunDockerCommand createExploratoryEnvironmentCommand = new RunDockerCommand()
+                .withVolumeForRootKeys(rootKeysVolume)
+                .withVolumeForResponse(responseVolume)
+                .withRequestId(requestID)
+                .withConfServiceBaseName(confServiceBaseName)
+                .withAwsRegion(credsRegion)
+                .withConfKeyName(credsKeyName)
+                .withNotebookUserName(notebookUserName)
+                .withNotebookSubnetCidr(notebookSubnetCidr)
+                .withAwsSecurityGroupsIds(credsSecurityGroupsIds)
+                .withActionCreate(toCreate);
+
+        assertEquals(
+                String.format(
+                        CREATE_EXPLORATORY_ENVIRONMENT,
+                        rootKeysVolume,
+                        responseVolume,
+                        requestID,
+                        confServiceBaseName,
+                        credsRegion,
+                        credsKeyName,
+                        notebookUserName,
+                        notebookSubnetCidr,
+                        credsSecurityGroupsIds,
+                        toCreate
+                ),
+                createExploratoryEnvironmentCommand.toCMD()
+        );
+    }
+
+    @Test
+    public void testTerminateExploratoryEnvironment() {
+        RunDockerCommand terminateExploratoryEnvironmentCommand = new RunDockerCommand()
+                .withVolumeForRootKeys(rootKeysVolume)
+                .withVolumeForResponse(responseVolume)
+                .withRequestId(requestID)
+                .withConfServiceBaseName(confServiceBaseName)
+                .withAwsRegion(credsRegion)
+                .withConfKeyName(credsKeyName)
+                .withNotebookUserName(notebookUserName)
+                .withNotebookInstanceName(notebookInstanceName)
+                .withActionTerminate(toTerminate);
+
+        assertEquals(
+                String.format(
+                        TERMINATE_EXPLORATORY_ENVIRONMENT,
+                        rootKeysVolume,
+                        responseVolume,
+                        requestID,
+                        confServiceBaseName,
+                        credsRegion,
+                        credsKeyName,
+                        notebookUserName,
+                        notebookInstanceName,
+                        toTerminate
+                ),
+                terminateExploratoryEnvironmentCommand.toCMD()
+        );
+    }
+
+    @Test
+    public void testStopExploratoryEnvironment() {
+        RunDockerCommand stopExploratoryEnvironmentCommand = new RunDockerCommand()
+                .withVolumeForRootKeys(rootKeysVolume)
+                .withVolumeForResponse(responseVolume)
+                .withRequestId(requestID)
+                .withConfServiceBaseName(confServiceBaseName)
+                .withAwsRegion(credsRegion)
+                .withConfKeyName(credsKeyName)
+                .withNotebookUserName(notebookUserName)
+                .withNotebookInstanceName(notebookInstanceName)
+                .withActionStop(toStop);
+
+        assertEquals(
+                String.format(
+                        STOP_EXPLORATORY_ENVIRONMENT,
+                        rootKeysVolume,
+                        responseVolume,
+                        requestID,
+                        confServiceBaseName,
+                        credsRegion,
+                        credsKeyName,
+                        notebookUserName,
+                        notebookInstanceName,
+                        toStop
+                ),
+                stopExploratoryEnvironmentCommand.toCMD()
+        );
+    }
+
+}
diff --git a/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/response/folderlistener/FolderListenerTest.java b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/response/folderlistener/FolderListenerTest.java
new file mode 100644
index 0000000..b7d4491
--- /dev/null
+++ b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/response/folderlistener/FolderListenerTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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.datalab.backendapi.core.response.folderlistener;
+
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.util.ServiceUtils;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+
+import static org.junit.Assert.assertEquals;
+
+public class FolderListenerTest {
+    private final long maxWaitTimeoutMillis = 30000;
+
+    private final long timeoutMillis = 2000;
+
+    private final long fileLengthCheckDelay = 1000;
+
+    private boolean handleResult = true;
+
+    public class FileHandler implements FileHandlerCallback {
+        private final String uuid;
+
+        public FileHandler(String uuid) {
+            this.uuid = uuid;
+        }
+
+        @Override
+        public String getUUID() {
+            return uuid;
+        }
+
+        @Override
+        public boolean checkUUID(String uuid) {
+            return this.uuid.equals(uuid);
+        }
+
+        @Override
+        public boolean handle(String fileName, byte[] content) throws Exception {
+            if (!handleResult) {
+                throw new Exception("Test exception");
+            }
+            return handleResult;
+        }
+
+        @Override
+        public void handleError(String errorMessage) {
+            System.out.println("handleError called for UUID " + getUUID());
+        }
+
+        @Override
+        public String getUser() {
+            return null;
+        }
+    }
+
+    private String getFileName(String uuid) {
+        return "FolderListenerTest_" + uuid + ".json";
+    }
+
+    private String getDirectory() {
+        return ServiceUtils.getUserDir();
+    }
+
+    private void removeFile(String uuid) throws IOException {
+        File file = new File(getDirectory(), getFileName(uuid));
+        if (file.exists()) {
+            file.delete();
+        }
+    }
+
+    private void createFile(String uuid) throws IOException {
+        File file = new File(getDirectory(), getFileName(uuid));
+        removeFile(uuid);
+        FileWriter f = new FileWriter(file);
+
+        f.write("test");
+        f.flush();
+        f.close();
+    }
+
+
+    private void processFile(WatchItem item) throws InterruptedException, IOException {
+        long expiredTime = System.currentTimeMillis() + maxWaitTimeoutMillis;
+        while (!FolderListener.getListeners().isEmpty() &&
+                !FolderListener.getListeners().get(0).isListen()) {
+            if (expiredTime < System.currentTimeMillis()) {
+                throw new InterruptedException("Timeout has been expired");
+            }
+            Thread.sleep(100);
+        }
+
+        expiredTime = System.currentTimeMillis() + maxWaitTimeoutMillis;
+        while (item.getFuture() == null) {
+            if (expiredTime < System.currentTimeMillis()) {
+                throw new InterruptedException("Timeout has been expired");
+            }
+            Thread.sleep(100);
+        }
+    }
+
+    @Test
+    public void listen() throws InterruptedException, ExecutionException, IOException {
+        Integer uuid = 1;
+        FileHandlerCallback fHandler;
+        WatchItem item;
+
+        handleResult = false;
+        fHandler = new FileHandler(uuid.toString());
+        item = FolderListener.listen(getDirectory(), fHandler, timeoutMillis, fileLengthCheckDelay, null);
+        FolderListener listener = FolderListener.getListeners().get(0);
+        assertEquals(false, listener.isListen());
+        assertEquals(true, listener.isAlive());
+        System.out.println("TEST process FALSE");
+
+        uuid = 2;
+        createFile(uuid.toString());
+        fHandler = new FileHandler(uuid.toString());
+        item = FolderListener.listen(getDirectory(), fHandler, timeoutMillis, fileLengthCheckDelay, null);
+        processFile(item);
+        assertEquals(true, listener.isListen());
+        assertEquals(false, item.getFutureResultSync());
+        assertEquals(false, item.getFutureResult());
+
+        System.out.println("TEST process TRUE");
+        uuid = 3;
+        handleResult = true;
+        createFile(uuid.toString());
+        fHandler = new FileHandler(uuid.toString());
+        item = FolderListener.listen(getDirectory(), fHandler, timeoutMillis, fileLengthCheckDelay, null);
+        processFile(item);
+        assertEquals(true, item.getFutureResultSync());
+        assertEquals(true, item.getFutureResult());
+
+        System.out.println("TEST process with out listen");
+        uuid = 4;
+        createFile(uuid.toString());
+        fHandler = new FileHandler(uuid.toString());
+        item = FolderListener.listen(getDirectory(), fHandler, timeoutMillis, fileLengthCheckDelay, getFileName(uuid
+                .toString()), null);
+
+        long expiredTime = System.currentTimeMillis() + maxWaitTimeoutMillis;
+        while (item.getFuture() == null) {
+            if (expiredTime < System.currentTimeMillis()) {
+                throw new InterruptedException("Timeout has been expired");
+            }
+            Thread.sleep(100);
+        }
+        assertEquals(true, item.getFutureResultSync());
+        assertEquals(true, item.getFutureResult());
+
+        FolderListener.terminateAll();
+        expiredTime = System.currentTimeMillis() + maxWaitTimeoutMillis;
+        while (FolderListener.getListeners().size() > 0) {
+            if (expiredTime < System.currentTimeMillis()) {
+                throw new InterruptedException("Timeout has been expired");
+            }
+            Thread.sleep(100);
+        }
+
+        System.out.println("All listen tests passed");
+
+
+        for (int i = 1; i <= uuid; i++) {
+            removeFile(String.valueOf(i));
+        }
+    }
+
+}
diff --git a/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/response/folderlistener/WatchItemListTest.java b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/response/folderlistener/WatchItemListTest.java
new file mode 100644
index 0000000..a50cf0d
--- /dev/null
+++ b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/response/folderlistener/WatchItemListTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.datalab.backendapi.core.response.folderlistener;
+
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.response.folderlistener.WatchItem.ItemStatus;
+import org.junit.Test;
+
+import java.util.concurrent.ExecutionException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class WatchItemListTest {
+
+    private static final String UUID = "123";
+
+    private final FileHandlerCallback fHandler = new FileHandler(UUID);
+
+    private final long timeoutMillis = 1000;
+
+    private final long fileLengthCheckDelay = 10000;
+
+    public class FileHandler implements FileHandlerCallback {
+        private final String uuid;
+
+        public FileHandler(String uuid) {
+            this.uuid = uuid;
+        }
+
+        @Override
+        public String getUUID() {
+            return uuid;
+        }
+
+        @Override
+        public boolean checkUUID(String uuid) {
+            return this.uuid.equals(uuid);
+        }
+
+        @Override
+        public boolean handle(String fileName, byte[] content) throws Exception {
+            return true;
+        }
+
+        @Override
+        public void handleError(String errorMessage) {
+            System.out.println("handleError called for UUID " + getUUID());
+        }
+
+        @Override
+        public String getUser() {
+            return null;
+        }
+    }
+
+
+    private String getDirectory() {
+        return "./";
+    }
+
+    private String getFileName() {
+        return UUID + ".json";
+    }
+
+    @Test
+    public void checkGetters() {
+        WatchItemList items = new WatchItemList(getDirectory(), null);
+
+        assertEquals(0, items.size());
+
+        items.append(fHandler, timeoutMillis, fileLengthCheckDelay);
+        assertEquals(1, items.size());
+
+        WatchItem item = items.get(0);
+        assertNotNull(item);
+        assertEquals(0, items.getIndex(UUID));
+        assertEquals(item, items.getItem(getFileName()));
+        items.remove(0);
+        assertEquals(0, items.size());
+    }
+
+
+    @Test
+    public void processItem() throws InterruptedException, ExecutionException {
+        WatchItemList items = new WatchItemList(getDirectory(), null);
+        items.append(fHandler, timeoutMillis, fileLengthCheckDelay);
+
+        WatchItem item = items.get(0);
+
+        assertEquals(false, items.processItem(item));
+
+        item.setFileName(getFileName());
+        assertEquals(true, items.processItem(item));
+
+        assertEquals(ItemStatus.INPROGRESS, item.getStatus());
+        item.getFutureResultSync();
+    }
+
+    @Test
+    public void processItemAll() throws InterruptedException, ExecutionException {
+        WatchItemList items = new WatchItemList(getDirectory(), null);
+        items.append(fHandler, timeoutMillis, fileLengthCheckDelay);
+
+        WatchItem item = items.get(0);
+
+        assertEquals(0, items.processItemAll());
+
+        item.setFileName(getFileName());
+        assertEquals(1, items.processItemAll());
+
+        assertEquals(ItemStatus.INPROGRESS, item.getStatus());
+        item.getFutureResultSync();
+    }
+
+}
diff --git a/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/response/folderlistener/WatchItemTest.java b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/response/folderlistener/WatchItemTest.java
new file mode 100644
index 0000000..075523d
--- /dev/null
+++ b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/response/folderlistener/WatchItemTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.datalab.backendapi.core.response.folderlistener;
+
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.response.folderlistener.WatchItem.ItemStatus;
+import io.dropwizard.util.Duration;
+import org.junit.Test;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import static org.junit.Assert.assertEquals;
+
+public class WatchItemTest {
+
+    private static final String UUID = "123";
+
+    private final FileHandlerCallback fHandler = new FileHandler(UUID);
+
+    private final long timeoutMillis = 1000;
+
+    private final long fileLengthCheckDelay = 10000;
+
+    public class FileHandler implements FileHandlerCallback {
+        private final String uuid;
+
+        public FileHandler(String uuid) {
+            this.uuid = uuid;
+        }
+
+        @Override
+        public String getUUID() {
+            return uuid;
+        }
+
+        @Override
+        public boolean checkUUID(String uuid) {
+            return this.uuid.equals(uuid);
+        }
+
+        @Override
+        public boolean handle(String fileName, byte[] content) throws Exception {
+            return true;
+        }
+
+        @Override
+        public void handleError(String errorMessage) {
+            System.out.println("handleError called for UUID " + getUUID());
+        }
+
+        @Override
+        public String getUser() {
+            return null;
+        }
+    }
+
+
+    private WatchItem getWatchItem() {
+        return new WatchItem(fHandler, timeoutMillis, fileLengthCheckDelay);
+    }
+
+    private String getFileName() {
+        return UUID + ".json";
+    }
+
+    private String getDirectory() {
+        return "./";
+    }
+
+    private AsyncFileHandler getSupplier(WatchItem item) {
+        return new AsyncFileHandler(item.getFileName(), getDirectory(), item.getFileHandlerCallback(),
+                Duration.milliseconds(item.getFileLengthCheckDelay()));
+    }
+
+    @Test
+    public void isExpired() {
+        WatchItem item;
+
+        item = new WatchItem(fHandler, -1, fileLengthCheckDelay);
+        assertEquals(true, item.isExpired());
+
+        item = getWatchItem();
+        assertEquals(false, item.isExpired());
+    }
+
+    @Test
+    public void status() throws InterruptedException, ExecutionException {
+        WatchItem item;
+
+        item = new WatchItem(fHandler, -1, fileLengthCheckDelay);
+        assertEquals(ItemStatus.TIMEOUT_EXPIRED, item.getStatus());
+
+        item.setFileName(getFileName());
+        assertEquals(ItemStatus.FILE_CAPTURED, item.getStatus());
+
+        item = getWatchItem();
+        assertEquals(ItemStatus.WAIT_FOR_FILE, item.getStatus());
+
+        item.setFileName(getFileName());
+        assertEquals(ItemStatus.FILE_CAPTURED, item.getStatus());
+
+        item.setFuture(CompletableFuture.supplyAsync(getSupplier(item)));
+        assertEquals(ItemStatus.INPROGRESS, item.getStatus());
+
+        assertEquals(null, item.getFutureResult());
+        item.getFutureResultSync();
+
+        assertEquals(ItemStatus.IS_DONE, item.getStatus());
+
+        item.setFuture(CompletableFuture.supplyAsync(getSupplier(item)));
+        item.getFuture().cancel(false);
+        assertEquals(ItemStatus.IS_CANCELED, item.getStatus());
+
+        //IS_INTERRUPTED, IS_FAILED
+    }
+
+    @Test
+    public void futureResult() throws InterruptedException, ExecutionException {
+        WatchItem item = getWatchItem();
+
+        item.setFileName(getFileName());
+        item.setFuture(CompletableFuture.supplyAsync(getSupplier(item)));
+
+        assertEquals(false, item.getFutureResultSync());
+        assertEquals(false, item.getFutureResult());
+    }
+}
diff --git a/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/response/handlers/dao/FileSystemCallbackHandlerDaoTest.java b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/response/handlers/dao/FileSystemCallbackHandlerDaoTest.java
new file mode 100644
index 0000000..8775fa7
--- /dev/null
+++ b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/core/response/handlers/dao/FileSystemCallbackHandlerDaoTest.java
@@ -0,0 +1,213 @@
+/*
+ * 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.datalab.backendapi.core.response.handlers.dao;
+
+import com.epam.datalab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.core.DockerWarmuper;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.response.handlers.LibListCallbackHandler;
+import com.epam.datalab.backendapi.core.response.handlers.PersistentFileHandler;
+import com.epam.datalab.exceptions.DatalabException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.refEq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class FileSystemCallbackHandlerDaoTest {
+
+    @Mock
+    private ObjectMapper mapper;
+    @Mock
+    private ProvisioningServiceApplicationConfiguration configuration;
+    @Mock
+    private CallbackHandlerDao dao;
+    @InjectMocks
+    private FileSystemCallbackHandlerDao fileSystemCallbackHandlerDao;
+
+    @Rule
+    public TemporaryFolder folder = new TemporaryFolder();
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Before
+    public void createHandlersFolder() throws IOException {
+        folder.newFolder("opt", "handlers");
+    }
+
+
+    @Test
+    public void upsert() throws IOException {
+        final String handlersFolders = getHandlersFolder();
+        when(configuration.getHandlerDirectory()).thenReturn(handlersFolders);
+        when(mapper.writeValueAsBytes(any())).thenReturn("{'test': 'test'}".getBytes());
+        final PersistentFileHandler persistentFileHandler =
+                new PersistentFileHandler(new LibListCallbackHandler(null,
+                        DockerAction.LIB_LIST, "uuid", "test", "das"), 1L, "/opt/test");
+
+        fileSystemCallbackHandlerDao.upsert(persistentFileHandler);
+
+        verify(configuration, times(2)).getHandlerDirectory();
+        verify(mapper).writeValueAsBytes(refEq(persistentFileHandler));
+        assertTrue(new File(handlersFolders + File.separator + "LibListCallbackHandler_uuid.json").exists());
+        verifyNoMoreInteractions(mapper, configuration, dao);
+    }
+
+    @Test
+    public void upsertTwoSimilarHandlers() throws IOException {
+        final String handlersFolders = getHandlersFolder();
+        when(configuration.getHandlerDirectory()).thenReturn(handlersFolders);
+        when(mapper.writeValueAsBytes(any())).thenReturn("{'test': 'test'}".getBytes());
+        final PersistentFileHandler persistentFileHandler1 = new PersistentFileHandler(new DockerWarmuper()
+                .new DockerFileHandlerCallback("sameUUID"), 1L, "/opt/test");
+        final PersistentFileHandler persistentFileHandler2 =
+                new PersistentFileHandler(new LibListCallbackHandler(null,
+                        DockerAction.LIB_LIST, "sameUUID", "test", "das1"), 1L, "/opt/test");
+        final PersistentFileHandler persistentFileHandler3 =
+                new PersistentFileHandler(new LibListCallbackHandler(null,
+                        DockerAction.LIB_LIST, "anotherUUID", "test", "das2"), 1L, "/opt/test");
+
+
+        fileSystemCallbackHandlerDao.upsert(persistentFileHandler1);
+        fileSystemCallbackHandlerDao.upsert(persistentFileHandler2);
+        fileSystemCallbackHandlerDao.upsert(persistentFileHandler3);
+
+        verify(configuration, times(6)).getHandlerDirectory();
+        verify(mapper).writeValueAsBytes(refEq(persistentFileHandler1));
+        verify(mapper).writeValueAsBytes(refEq(persistentFileHandler2));
+        verify(mapper).writeValueAsBytes(refEq(persistentFileHandler3));
+        assertTrue(new File(handlersFolders + File.separator + "LibListCallbackHandler_sameUUID.json").exists());
+        assertTrue(new File(handlersFolders + File.separator + "LibListCallbackHandler_anotherUUID.json").exists());
+        assertFalse(new File(handlersFolders + File.separator + "DockerFileHandlerCallback_sameUUID.json").exists());
+        verifyNoMoreInteractions(mapper, configuration, dao);
+    }
+
+    @Test
+    public void findAll() throws IOException {
+        final File handler1 = getHandlerFile("test1.json");
+        final File handler2 = getHandlerFile("test2.json");
+        final String handlersFolder = getHandlersFolder();
+
+        when(configuration.getHandlerDirectory()).thenReturn(handlersFolder);
+        final PersistentFileHandler persistentFileHandler1 = new PersistentFileHandler(null, 1L, "/opt");
+        final PersistentFileHandler persistentFileHandler2 = new PersistentFileHandler(null, 2L, "/opt");
+        when(mapper.readValue(any(File.class), Matchers.<Class<PersistentFileHandler>>any())).thenReturn
+                (persistentFileHandler1).thenReturn(persistentFileHandler2);
+        final List<PersistentFileHandler> handlers = fileSystemCallbackHandlerDao.findAll();
+
+        assertEquals(2, handlers.size());
+
+        verify(configuration).getHandlerDirectory();
+        verify(mapper).readValue(handler1, PersistentFileHandler.class);
+        verify(mapper).readValue(handler2, PersistentFileHandler.class);
+        verifyNoMoreInteractions(mapper, dao, configuration);
+    }
+
+    @Test
+    public void findAllWithException() throws IOException {
+        new File(getHandlersFolder()).delete();
+        when(configuration.getHandlerDirectory()).thenReturn(getHandlersFolder());
+        when(mapper.readValue(any(File.class), Matchers.<Class<PersistentFileHandler>>any())).thenThrow(new
+                RuntimeException("Exception"));
+        final List<PersistentFileHandler> handlers = fileSystemCallbackHandlerDao.findAll();
+
+        assertEquals(0, handlers.size());
+
+        verify(configuration).getHandlerDirectory();
+        verifyNoMoreInteractions(mapper, dao, configuration);
+    }
+
+    @Test
+    public void findAllWithOneWrongHandlerFile() throws IOException {
+        final File handler1 = getHandlerFile("test1.json");
+        final File handler2 = getHandlerFile("test2.json");
+        final String handlersFolder = getHandlersFolder();
+
+        final PersistentFileHandler persistentFileHandler1 = new PersistentFileHandler(null, 1L, "/opt");
+
+        when(configuration.getHandlerDirectory()).thenReturn(handlersFolder);
+        when(mapper.readValue(any(File.class), Matchers.<Class<PersistentFileHandler>>any())).thenReturn
+                (persistentFileHandler1).thenThrow(new RuntimeException("Exception"));
+
+        final List<PersistentFileHandler> handlers = fileSystemCallbackHandlerDao.findAll();
+
+        assertEquals(1, handlers.size());
+
+        verify(configuration).getHandlerDirectory();
+        verify(mapper).readValue(handler1, PersistentFileHandler.class);
+        verify(mapper).readValue(handler2, PersistentFileHandler.class);
+        verifyNoMoreInteractions(mapper, dao, configuration);
+    }
+
+    private String getHandlersFolder() {
+        return folder.getRoot().getAbsolutePath() +
+                File.separator + "opt" + File.separator + "handlers";
+    }
+
+    private File getHandlerFile(String handlerFileName) throws IOException {
+        return folder.newFile(File.separator + "opt" + File.separator + "handlers" + File.separator +
+                handlerFileName);
+    }
+
+    @Test
+    public void remove() throws IOException {
+        final File handler = getHandlerFile("test1.json");
+        handler.createNewFile();
+        final String handlersFolder = getHandlersFolder();
+
+        when(configuration.getHandlerDirectory()).thenReturn(handlersFolder);
+        fileSystemCallbackHandlerDao.remove("test1");
+
+        assertFalse(handler.exists());
+
+        verify(configuration).getHandlerDirectory();
+        verifyNoMoreInteractions(configuration, dao, mapper);
+    }
+
+    @Test
+    public void removeWithException() throws IOException {
+        final String handlersFolder = getHandlersFolder();
+
+        when(configuration.getHandlerDirectory()).thenReturn(handlersFolder);
+        expectedException.expect(DatalabException.class);
+        fileSystemCallbackHandlerDao.remove("test1.json");
+    }
+}
\ No newline at end of file
diff --git a/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/service/RestoreCallbackHandlerServiceImplTest.java b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/service/RestoreCallbackHandlerServiceImplTest.java
new file mode 100644
index 0000000..1df6778
--- /dev/null
+++ b/services/provisioning-service/src/test/java/com/epam/datalab/backendapi/service/RestoreCallbackHandlerServiceImplTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.backendapi.core.response.folderlistener.FolderListenerExecutor;
+import com.epam.datalab.backendapi.core.response.handlers.PersistentFileHandler;
+import com.epam.datalab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
+import com.epam.datalab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
+import io.dropwizard.util.Duration;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Arrays;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RestoreCallbackHandlerServiceImplTest {
+
+    @Mock
+    private CallbackHandlerDao dao;
+    @Mock
+    private FolderListenerExecutor folderListenerExecutor;
+    @InjectMocks
+    private RestoreCallbackHandlerServiceImpl restoreCallbackHandlerService;
+
+    @Test
+    public void start() throws Exception {
+
+        final PersistentFileHandler handler1 = new PersistentFileHandler(null, 1L, "test");
+        final PersistentFileHandler handler2 = new PersistentFileHandler(null, 2L, "test1");
+        when(dao.findAll()).thenReturn(Arrays.asList(handler1, handler2));
+
+        restoreCallbackHandlerService.start();
+
+        verify(dao).findAll();
+        verify(folderListenerExecutor).start(handler1.getDirectory(), Duration.milliseconds(handler1.getTimeout()),
+                handler1.getHandler());
+        verify(folderListenerExecutor).start(handler2.getDirectory(), Duration.milliseconds(handler2.getTimeout()),
+                handler2.getHandler());
+        verifyNoMoreInteractions(dao, folderListenerExecutor);
+    }
+}
\ No newline at end of file
diff --git a/services/provisioning-service/src/test/java/com/epam/datalab/rest/client/RESTServiceMock.java b/services/provisioning-service/src/test/java/com/epam/datalab/rest/client/RESTServiceMock.java
new file mode 100644
index 0000000..7df16dd
--- /dev/null
+++ b/services/provisioning-service/src/test/java/com/epam/datalab/rest/client/RESTServiceMock.java
@@ -0,0 +1,41 @@
+/*
+ * 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.datalab.rest.client;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RESTServiceMock extends RESTService {
+
+    private final static Logger LOG = LoggerFactory.getLogger(RESTService.class);
+
+    @Override
+    public <T> T post(String path, Object parameter, Class<T> clazz) {
+        LOG.debug("REST POST {},\n object {},\n response class {}", path, parameter, clazz.getName());
+        try {
+            return (T) clazz.newInstance();
+        } catch (InstantiationException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+}
diff --git a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/DockerWarmuperTest.java b/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/DockerWarmuperTest.java
deleted file mode 100644
index 16ac19c..0000000
--- a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/DockerWarmuperTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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.core;
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
-import com.epam.dlab.backendapi.core.response.folderlistener.FolderListenerExecutor;
-import com.epam.dlab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
-import com.epam.dlab.dto.imagemetadata.*;
-import com.epam.dlab.process.model.ProcessInfo;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import io.dropwizard.util.Duration;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-import static junit.framework.TestCase.assertEquals;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class DockerWarmuperTest {
-	@Inject
-	private DockerWarmuper warmuper;
-	private ExploratoryMetadataDTO exploratoryMetadata = new ExploratoryMetadataDTO(
-			"executeResult");
-	private ComputationalMetadataDTO computationalMetadata = new
-			ComputationalMetadataDTO("executeResult");
-	private static final String EXPLORATORY_TEST_JSON = "{\"exploratory_environment_shapes\" : { \"Category\" : [ " +
-			"{\"Size\":\"L\", \"Type\":\"cg1.4xlarge\",\"Ram\": \"22.5 GB\",\"Cpu\": \"16\"}]}}";
-	private static final String COMPUTATIONAL_TEST_JSON = "{\"template_name\":\"EMR cluster\"}";
-
-	@Before
-	public void setup() {
-		createInjector().injectMembers(this);
-		ComputationalResourceShapeDto computationalResourceShapeDto = new ComputationalResourceShapeDto();
-		computationalResourceShapeDto.setSize("L");
-		computationalResourceShapeDto.setType("cg1.4xlarge");
-		computationalResourceShapeDto.setRam("22.5 GB");
-		computationalResourceShapeDto.setCpu(16);
-		List<ComputationalResourceShapeDto> metadataArray = new ArrayList<>();
-		metadataArray.add(computationalResourceShapeDto);
-		HashMap<String, List<ComputationalResourceShapeDto>> map = new HashMap<>();
-		map.put("Category", metadataArray);
-		exploratoryMetadata.setExploratoryEnvironmentShapes(map);
-		computationalMetadata.setTemplateName("EMR cluster");
-	}
-
-	@Test
-	public void warmupSuccess() throws Exception {
-		warmuper.start();
-		warmuper.getFileHandlerCallback(getFirstUUID())
-				.handle(getFileName(), EXPLORATORY_TEST_JSON.getBytes());
-		warmuper.getFileHandlerCallback(getFirstUUID())
-				.handle(getFileName(), COMPUTATIONAL_TEST_JSON.getBytes());
-
-		ImageMetadataDTO testExploratory = warmuper.getMetadata(ImageType.EXPLORATORY)
-				.toArray(new ImageMetadataDTO[1])[0];
-		testExploratory.setImage("executeResult");
-		assertEquals(exploratoryMetadata.getImageType(), testExploratory.getImageType());
-
-		ImageMetadataDTO testComputational = warmuper.getMetadata(ImageType.COMPUTATIONAL)
-				.toArray(new ImageMetadataDTO[1])[0];
-		testComputational.setImage("executeResult");
-		assertEquals(computationalMetadata.getImageType(), testComputational.getImageType());
-	}
-
-	private String getFirstUUID() {
-		return warmuper.getUuids().keySet().toArray(new String[1])[0];
-	}
-
-	private String getFileName() {
-		return getFirstUUID() + ".json";
-	}
-
-	private Injector createInjector() {
-		return Guice.createInjector(new AbstractModule() {
-			@Override
-			protected void configure() {
-				bind(FolderListenerExecutor.class).toInstance(mock(FolderListenerExecutor.class));
-				bind(ProvisioningServiceApplicationConfiguration.class).toInstance(createConfiguration());
-				bind(ICommandExecutor.class).toInstance(createCommandExecutor());
-				bind(CallbackHandlerDao.class).toInstance(mock(CallbackHandlerDao.class));
-			}
-		});
-	}
-
-	private ProvisioningServiceApplicationConfiguration createConfiguration() {
-		ProvisioningServiceApplicationConfiguration result = mock(ProvisioningServiceApplicationConfiguration.class);
-		when(result.getWarmupDirectory()).thenReturn("/tmp");
-		when(result.getWarmupPollTimeout()).thenReturn(Duration.seconds(3));
-		return result;
-	}
-
-	private ICommandExecutor createCommandExecutor() {
-		ICommandExecutor result = mock(ICommandExecutor.class);
-		try {
-			final ProcessInfo pi = mock(ProcessInfo.class);
-			when(pi.getStdOut()).thenReturn("executeResult");
-			when(result.executeSync(anyString(), anyString(), anyString())).thenReturn(pi);
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-		return result;
-	}
-}
diff --git a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMockTest.java b/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMockTest.java
deleted file mode 100644
index a065248..0000000
--- a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMockTest.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * 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.core.commands;
-
-import com.epam.dlab.backendapi.core.response.handlers.ExploratoryCallbackHandler;
-import com.epam.dlab.backendapi.core.response.handlers.LibListCallbackHandler;
-import com.epam.dlab.backendapi.core.response.handlers.ResourceCallbackHandler;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.rest.client.RESTServiceMock;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.UUID;
-import java.util.concurrent.ExecutionException;
-
-@Ignore
-public class CommandExecutorMockTest {
-	private CommandExecutorMock getCommandExecutor() {
-		return new CommandExecutorMock(CloudProvider.AWS);
-	}
-
-	private CommandExecutorMock executeAsync(String cmd) throws IOException, InterruptedException, ExecutionException {
-		String uuid = UUID.randomUUID().toString();
-		CommandExecutorMock exec = new CommandExecutorMock(CloudProvider.AWS);
-		exec.executeAsync("user", uuid, cmd);
-		exec.getResultSync();
-
-		Files.deleteIfExists(Paths.get(exec.getResponseFileName()));
-
-		return exec;
-	}
-
-	private String getRequestId(CommandExecutorMock exec) {
-		return exec.getVariables().get("request_id");
-	}
-
-	private String getEdgeUserName(CommandExecutorMock exec) {
-		return exec.getVariables().get("edge_user_name");
-	}
-
-	private String getExploratoryName(CommandExecutorMock exec) {
-		return exec.getVariables().get("exploratory_name");
-	}
-
-	private void handleExploratory(String cmd, DockerAction action) throws Exception {
-		String uuid = UUID.randomUUID().toString();
-		CommandExecutorMock exec = getCommandExecutor();
-		exec.executeAsync("user", uuid, cmd);
-		exec.getResultSync();
-
-		RESTServiceMock selfService = new RESTServiceMock();
-		ExploratoryCallbackHandler handler = new ExploratoryCallbackHandler(selfService, action,
-				getRequestId(exec), getEdgeUserName(exec), "", getExploratoryName(exec));
-		handler.handle(exec.getResponseFileName(), Files.readAllBytes(Paths.get(exec.getResponseFileName())));
-
-		try {
-			Files.deleteIfExists(Paths.get(exec.getResponseFileName()));
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-	}
-
-	private void handleExploratoryLibs(String cmd, DockerAction action) throws Exception {
-		String uuid = UUID.randomUUID().toString();
-		CommandExecutorMock exec = getCommandExecutor();
-		exec.executeAsync("user", uuid, cmd);
-		exec.getResultSync();
-
-		RESTServiceMock selfService = new RESTServiceMock();
-		if (action == DockerAction.LIB_INSTALL) {
-			throw new Exception("Unimplemented action " + action);
-		}
-		/*
-		ResourceCallbackHandler<?> handler = action.equals(DockerAction.LIB_INSTALL) ?
-				new LibInstallCallbackHandler(selfService, action,
-				getRequestId(exec), getEdgeUserName(exec), getExploratoryName(exec)):
-				new LibListCallbackHandler(selfService, action,
-				getRequestId(exec), getEdgeUserName(exec), getExploratoryName(exec));
-		*/
-		ResourceCallbackHandler<?> handler = new LibListCallbackHandler(selfService, action, getRequestId(exec),
-				getEdgeUserName(exec), getExploratoryName(exec));
-
-		handler.handle(exec.getResponseFileName(), Files.readAllBytes(Paths.get(exec.getResponseFileName())));
-
-		try {
-			Files.deleteIfExists(Paths.get(exec.getResponseFileName()));
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-	}
-
-	@Test
-	public void describe() throws IOException, InterruptedException, ExecutionException {
-		String cmd =
-				"docker run " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/notebook:/logs/notebook " +
-						"-e \"conf_resource=notebook\" " +
-						"-e \"request_id=28ba67a4-b2ee-4753-a406-892977089ad9\" " +
-						"docker.dlab-zeppelin:latest --action describe";
-		executeAsync(cmd);
-	}
-
-	@Test
-	public void edgeCreate() throws IOException, InterruptedException, ExecutionException {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"," +
-						"\"conf_service_base_name\":\"usein1120v13\",\"conf_os_family\":\"debian\"," +
-						"\"aws_vpc_id\":\"vpc-83c469e4\",\"aws_subnet_id\":\"subnet-22db937a\"," +
-						"\"aws_security_groups_ids\":\"sg-4d42dc35\"}' | " +
-						"docker run -i --name user_create_edge_1487309918496 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/edge:/logs/edge " +
-						"-e \"conf_resource=edge\" " +
-						"-e \"request_id=b8267ae6-07b0-44ef-a489-7714b20cf0a4\" " +
-						"-e \"conf_key_name=BDCC-DSS-POC\" " +
-						"docker.dlab-edge --action create";
-		executeAsync(cmd);
-	}
-
-	@Test
-	public void edgeStop() throws IOException, InterruptedException, ExecutionException {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"," +
-						"\"conf_service_base_name\":\"usein1122v4\",\"conf_os_family\":\"debian\"}' | " +
-						"docker run -i --name user_stop_edge_1487677431773 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/edge:/logs/edge " +
-						"-e \"conf_resource=edge\" " +
-						"-e \"request_id=2ba3d8f7-654b-48aa-9386-e815b296a957\" " +
-						"-e \"conf_key_name=BDCC-DSS-POC\" " +
-						"docker.dlab-edge --action stop";
-		executeAsync(cmd);
-	}
-
-	@Test
-	public void edgeStart() throws IOException, InterruptedException, ExecutionException {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"," +
-						"\"conf_service_base_name\":\"usein1122v4\",\"conf_os_family\":\"debian\"}' | " +
-						"docker run -i --name user_start_edge_1487677538220 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/edge:/logs/edge " +
-						"-e \"conf_resource=edge\" " +
-						"-e \"request_id=d2f6fbae-979e-4b08-9c0d-559a103ec0cc\" " +
-						"-e \"conf_key_name=BDCC-DSS-POC\" " +
-						"docker.dlab-edge --action start";
-		executeAsync(cmd);
-	}
-
-	@Test
-	public void edgeStatus() throws IOException, InterruptedException, ExecutionException {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"," +
-						"\"edge_list_resources\":{\"host\":[{\"id\":\"i-05c1a0d0ad030cdc1\"}, " +
-						"{\"id\":\"i-05c1a0d0ad030cdc2\"}]}}' | " +
-						"docker run -i --name user_status_resources_1487607145484 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/edge:/logs/edge " +
-						"-e \"conf_resource=status\" " +
-						"-e \"request_id=0fb82e16-deb2-4b18-9ab3-f9f1c12d9e62\" " +
-						"-e \"conf_key_name=BDCC-DSS-POC\" " +
-						"docker.dlab-edge --action status";
-		executeAsync(cmd);
-	}
-
-
-	@Test
-	public void notebookCreate() throws Exception {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"," +
-						"\"conf_service_base_name\":\"usein1120v13\",\"conf_os_family\":\"debian\"," +
-						"\"exploratory_name\":\"useinxz1\",\"application\":\"zeppelin\",\"notebook_image\":\"docker" +
-						".dlab-zeppelin\"," +
-						"\"aws_notebook_instance_type\":\"t2.medium\",\"aws_security_groups_ids\":\"sg-4d42dc35\"}' " +
-						"|" +
-						" " +
-						"docker run -i --name user_create_exploratory_useinxz1_1487312574572 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/notebook:/logs/notebook " +
-						"-e \"conf_resource=notebook\" " +
-						"-e \"request_id=f720f30b-5949-4919-a50b-ce7af58d6fe9\" " +
-						"-e \"conf_key_name=BDCC-DSS-POC\" " +
-						"docker.dlab-zeppelin --action create";
-		handleExploratory(cmd, DockerAction.CREATE);
-	}
-
-	@Test
-	public void notebookStop() throws Exception {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"," +
-						"\"conf_service_base_name\":\"usein1120v13\"," +
-						"\"exploratory_name\":\"useinxz1\",\"notebook_image\":\"docker.dlab-zeppelin\"," +
-						"\"notebook_instance_name\":\"usein1120v13-user-nb-useinxz1-78af3\"," +
-						"\"conf_key_dir\":\"/root/keys\"}' | " +
-						"docker run -i --name user_stop_exploratory_useinxz1_1487315364165 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/notebook:/logs/notebook " +
-						"-e \"conf_resource=notebook\" " +
-						"-e \"request_id=33998e05-7781-432e-b748-bf3f0e7f9342\" " +
-						"-e \"conf_key_name=BDCC-DSS-POC\" " +
-						"docker.dlab-zeppelin --action stop";
-		handleExploratory(cmd, DockerAction.STOP);
-	}
-
-	@Test
-	public void notebookStart() throws Exception {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"," +
-						"\"conf_service_base_name\":\"usein1120v13\",\"conf_os_family\":\"debian\"," +
-						"\"exploratory_name\":\"useinxz1\",\"notebook_image\":\"docker.dlab-zeppelin\"," +
-						"\"notebook_instance_name\":\"usein1120v13-user-nb-useinxz1-78af3\"}' | " +
-						"docker run -i --name user_start_exploratory_useinxz1_1487316756857 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/notebook:/logs/notebook " +
-						"-e \"conf_resource=notebook\" " +
-						"-e \"request_id=d50b9d20-1b1a-415f-8e47-ed0aca029e73\" " +
-						"-e \"conf_key_name=BDCC-DSS-POC\" " +
-						"docker.dlab-zeppelin --action start";
-		handleExploratory(cmd, DockerAction.START);
-	}
-
-	@Test
-	public void notebookTerminate() throws Exception {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"," +
-						"\"conf_service_base_name\":\"usein1120v13\",\"conf_os_family\":\"debian\"," +
-						"\"exploratory_name\":\"useinxz1\",\"notebook_image\":\"docker.dlab-zeppelin\"," +
-						"\"notebook_instance_name\":\"usein1120v13-user-nb-useinxz1-78af3\"}' | " +
-						"docker run -i --name user_terminate_exploratory_useinxz1_1487318040180 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/notebook:/logs/notebook " +
-						"-e \"conf_resource=notebook\" " +
-						"-e \"request_id=de217441-9757-4c4e-b020-548f66b58e00\" " +
-						"-e \"conf_key_name=BDCC-DSS-POC\" " +
-						"docker.dlab-zeppelin --action terminate";
-		handleExploratory(cmd, DockerAction.TERMINATE);
-	}
-
-
-	@Test
-	public void emrCreate() throws Exception {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"," +
-						"\"conf_service_base_name\":\"usein1122v3\",\"conf_os_family\":\"debian\"," +
-						"\"exploratory_name\":\"useinj1\",\"application\":\"jupyter\"," +
-						"\"computational_name\":\"useine1\"," +
-						"\"emr_instance_count\":\"2\",\"emr_master_instance_type\":\"c4.large\"," +
-						"\"emr_slave_instance_type\":\"c4.large\"," +
-						"\"emr_version\":\"emr-5.2.0\",\"notebook_instance_name\":\"usein1122v3-user-nb-useinj1" +
-						"-1b198" +
-						"\"," +
-						"\"notebook_template_name\":\"Jupyter 1.5\"}' | " +
-						"docker run -i --name user_create_computational_useine1_1487653987822 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/emr:/logs/emr " +
-						"-e \"conf_resource=emr\" " +
-						"-e \"request_id=917db3fd-3c17-4e79-8462-482a71a5d96f\" " +
-						"-e \"ec2_role=EMR_EC2_DefaultRole\" " +
-						"-e \"emr_timeout=3600\" " +
-						"-e \"service_role=EMR_DefaultRole\" " +
-						"-e \"conf_key_name=BDCC-DSS-POC\" " +
-						"docker.dlab-emr --action create";
-		executeAsync(cmd);
-	}
-
-	@Test
-	public void emrConfigure() throws Exception {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"," +
-						"\"conf_service_base_name\":\"usein1122v4\",\"exploratory_name\":\"useinj1\"," +
-						"\"application\":\"jupyter\",\"computational_name\":\"useine2\",\"emr_version\":\"emr-5.2" +
-						".0\"," +
-						"\"notebook_instance_name\":\"usein1122v4-user-nb-useinj1-b0a2e\"}' | " +
-						"docker run -i --name user_configure_computational_useine2_1487676513703 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/emr:/logs/emr " +
-						"-e \"conf_resource=emr\" " +
-						"-e \"request_id=dc3c1002-c07d-442b-99f9-18085aeb2881\" " +
-						"-e \"conf_key_name=BDCC-DSS-POC\" " +
-						"docker.dlab-jupyter --action configure";
-		executeAsync(cmd);
-	}
-
-	@Test
-	public void emrTerminate() throws Exception {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"" +
-						",\"conf_service_base_name\":\"usein1122v3\",\"exploratory_name\":\"useinj1\"," +
-						"\"computational_name\":\"useine1\"," +
-						"\"emr_cluster_name\":\"usein1122v3-user-emr-useinj1-useine1-d2db9\"," +
-						"\"notebook_instance_name\":\"usein1122v3-user-nb-useinj1-1b198\"," +
-						"\"conf_key_dir\":\"/root/keys\"}' | " +
-						"docker run -i --name user_terminate_computational_useine1_1487657251858 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/emr:/logs/emr " +
-						"-e \"conf_resource=emr\" " +
-						"-e \"request_id=2d5c23b8-d312-4fad-8a3c-0b813550d841\" " +
-						"-e \"conf_key_name=BDCC-DSS-POC\" " +
-						"docker.dlab-emr --action terminate";
-		executeAsync(cmd);
-	}
-
-
-	@Test
-	public void listLibs() throws Exception {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"" +
-						",\"conf_service_base_name\":\"usein1122v3\",\"exploratory_name\":\"useinj1\"," +
-						"\"computational_name\":\"useine1\"," +
-						"\"emr_cluster_name\":\"usein1122v3-user-emr-useinj1-useine1-d2db9\"," +
-						"\"notebook_instance_name\":\"usein1122v3-user-nb-useinj1-1b198\"," +
-						"\"conf_key_dir\":\"/root/keys\"}' | " +
-						"docker run -i --name user_terminate_computational_useine1_1487657251858 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/emr:/logs/emr " +
-						"-e \"conf_resource=notebook\" " +
-						"-e \"request_id=2d5c23b8-d312-4fad-8a3c-0b813550d841\" " +
-						"-e \"conf_key_name=BDCC-DSS-POC\" " +
-						"-e \"application=jupyter\" " +
-						"docker.dlab-jupyter --action lib_list";
-		executeAsync(cmd);
-		handleExploratoryLibs(cmd, DockerAction.LIB_LIST);
-	}
-
-	@Test
-	public void installLibs() throws Exception {
-		String cmd =
-				"echo -e '{\"aws_region\":\"us-west-2\",\"aws_iam_user\":\"user@epam.com\"," +
-						"\"edge_user_name\":\"user\"" +
-						",\"conf_service_base_name\":\"usein1122v3\",\"exploratory_name\":\"useinj1\"," +
-						"\"computational_name\":\"useine1\"," +
-						"\"emr_cluster_name\":\"usein1122v3-user-emr-useinj1-useine1-d2db9\"," +
-						"\"notebook_instance_name\":\"usein1122v3-user-nb-useinj1-1b198\"," +
-						"\"conf_key_dir\":\"/root/keys\"}' | " +
-						"docker run -i --name user_terminate_computational_useine1_1487657251858 " +
-						"-v /home/ubuntu/keys:/root/keys " +
-						"-v /opt/dlab/tmp/result:/response " +
-						"-v /var/opt/dlab/log/emr:/logs/emr " +
-						"-e \"conf_resource=notebook\" " +
-						"-e \"additional_libs={'libraries': {\n" +
-						"\t\t\t\t'os_pkg': ['nmap', 'htop'],\n" +
-						"\t\t\t\t'pip2': ['requests', 'configparser'],\n" +
-						"\t\t\t\t'pip3': ['configparser'],\n" +
-						"\t\t\t\t'r_pkg': ['rmarkdown']\n" +
-						"\t\t\t\t}\n" +
-						"\t\t\t\t}\" " +
-						"docker.dlab-jupyter --action lib_install";
-		executeAsync(cmd);
-		handleExploratoryLibs(cmd, DockerAction.LIB_INSTALL);
-	}
-
-}
diff --git a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/docker/command/ImagesDockerCommandTest.java b/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/docker/command/ImagesDockerCommandTest.java
deleted file mode 100644
index 7656ac3..0000000
--- a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/docker/command/ImagesDockerCommandTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.core.docker.command;
-
-import com.epam.dlab.backendapi.core.commands.ImagesDockerCommand;
-import com.epam.dlab.backendapi.core.commands.UnixCommand;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class ImagesDockerCommandTest {
-
-    String GET_IMAGES = "docker images | awk '{print $1\":\"$2}' | sort | uniq | grep \"dlab\" | grep -v \"none\" | grep -v \"edge\"";
-
-    @Test
-    public void testBuildGetImagesCommand() {
-        String getImagesCommand = new ImagesDockerCommand()
-                .pipe(UnixCommand.awk("{print $1\":\"$2}"))
-                .pipe(UnixCommand.sort())
-                .pipe(UnixCommand.uniq())
-                .pipe(UnixCommand.grep("dlab"))
-                .pipe(UnixCommand.grep("none", "-v"))
-                .pipe(UnixCommand.grep("edge", "-v"))
-                .toCMD();
-        assertEquals(GET_IMAGES, getImagesCommand);
-    }
-}
diff --git a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/docker/command/RunDockerCommandTest.java b/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/docker/command/RunDockerCommandTest.java
deleted file mode 100644
index 068c0c1..0000000
--- a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/docker/command/RunDockerCommandTest.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * 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.core.docker.command;
-
-import com.epam.dlab.backendapi.core.commands.RunDockerCommand;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class RunDockerCommandTest {
-
-    String DOCKER_BASE = "docker run -v %s:/root/keys -v %s:/response -e \"request_id=%s\" ";
-
-    String GET_IMAGE_METADATA = DOCKER_BASE + "%s --action describe";
-
-    String RUN_IMAGE = DOCKER_BASE + "-e \"dry_run=true\" %s --action run";
-
-    String CREATE_EDGE_METADATA = DOCKER_BASE +
-            "-e \"conf_service_base_name=%s\" " +
-            "-e \"conf_key_name=%s\" " +
-            "-e \"edge_user_name=%s\" " +
-            "%s --action create";
-
-    String CREATE_EMR_CLUSTER = DOCKER_BASE +
-            "-e \"conf_service_base_name=%s\" " +
-            "-e \"emr_instance_count=%s\" " +
-            "-e \"emr_instance_type=%s\" " +
-            "-e \"emr_version=%s\" " +
-            "-e \"ec2_role=%s\" " +
-            "-e \"service_role=%s\" " +
-            "-e \"notebook_name=%s\" " +
-            "-e \"edge_user_name=%s\" " +
-            "-e \"edge_subnet_cidr=%s\" " +
-            "-e \"aws_region=%s\" " +
-            "-e \"conf_key_name=%s\" " +
-            "%s --action create";
-
-    String TERMINATE_EMR_CLUSTER = DOCKER_BASE +
-            "-e \"conf_service_base_name=%s\" " +
-            "-e \"edge_user_name=%s\" " +
-            "-e \"emr_cluster_name=%s\" " +
-            "-e \"aws_region=%s\" " +
-            "-e \"conf_key_name=%s\" " +
-            "%s --action terminate";
-
-    String EXPLORATORY_ENVIRONMENT = DOCKER_BASE +
-            "-e \"conf_service_base_name=%s\" " +
-            "-e \"aws_region=%s\" " +
-            "-e \"conf_key_name=%s\" ";
-
-    String CREATE_EXPLORATORY_ENVIRONMENT = EXPLORATORY_ENVIRONMENT +
-            "-e \"edge_user_name=%s\" " +
-            "-e \"notebook_subnet_cidr=%s\" " +
-            "-e \"aws_security_groups_ids=%s\" " +
-            "%s --action create";
-
-    String TERMINATE_EXPLORATORY_ENVIRONMENT = EXPLORATORY_ENVIRONMENT +
-            "-e \"edge_user_name=%s\" " +
-            "-e \"notebook_instance_name=%s\" " +
-            "%s --action terminate";
-
-    String STOP_EXPLORATORY_ENVIRONMENT = EXPLORATORY_ENVIRONMENT +
-            "-e \"edge_user_name=%s\" " +
-            "-e \"notebook_instance_name=%s\" " +
-            "%s --action stop";
-
-    String rootKeysVolume = "rkv";
-    String responseVolume = "rv";
-    String requestID = "rID";
-    String toDescribe = "tds";
-    String credsKeyName = "ckn";
-    String confServiceBaseName = "csbn";
-    String edgeUserName = "eun";
-    String userKeyName = "ukn";
-    String toCreate = "tc";
-    String toTerminate = "tt";
-    String toStop = "ts";
-    String toRun = "tr";
-    String emrInstanceCount = "10";
-    String emrInstanceType = "emit";
-    String emrVersion = "ev";
-    String ec2Role = "e2r";
-    String serviceRole = "sr";
-    String notebookName = "nn";
-    String edgeSubnetCidr = "esc";
-    String credsRegion = "cr";
-    String emrClusterName = "ecn";
-    String notebookUserName = "nun";
-    String notebookSubnetCidr = "nsc";
-    String credsSecurityGroupsIds = "csgi";
-    String notebookInstanceName = "nin";
-
-    @Test
-    public void testBuildDockerBaseCommand() {
-        RunDockerCommand dockerBaseCommand = new RunDockerCommand()
-                .withVolumeForRootKeys(rootKeysVolume)
-                .withVolumeForResponse(responseVolume)
-                .withRequestId(requestID);
-        assertEquals(String.format(DOCKER_BASE, rootKeysVolume, responseVolume, requestID), dockerBaseCommand.toCMD() + " ");
-    }
-
-    @Test
-    public void testBuildGetImageMetadataCommand() {
-        RunDockerCommand getImageMetadataCommand = new RunDockerCommand()
-                .withVolumeForRootKeys(rootKeysVolume)
-                .withVolumeForResponse(responseVolume)
-                .withRequestId(requestID)
-                .withActionDescribe(toDescribe);
-        assertEquals(String.format(GET_IMAGE_METADATA, rootKeysVolume, responseVolume, requestID, toDescribe), getImageMetadataCommand.toCMD());
-    }
-
-    @Test
-    public void testBuildCreateEdgeMetadataCommand() {
-        RunDockerCommand createEdgeMetadataCommand = new RunDockerCommand()
-                .withVolumeForRootKeys(rootKeysVolume)
-                .withVolumeForResponse(responseVolume)
-                .withRequestId(requestID)
-                .withConfServiceBaseName(confServiceBaseName)
-                .withConfKeyName(credsKeyName)
-                .withEdgeUserName(edgeUserName)
-                .withActionCreate(toCreate);
-        assertEquals(String.format(CREATE_EDGE_METADATA, rootKeysVolume, responseVolume,
-                requestID, confServiceBaseName, credsKeyName, edgeUserName, toCreate),
-                createEdgeMetadataCommand.toCMD());
-    }
-
-    @Test
-    public void testBuildRunImageCommand() {
-        RunDockerCommand runImageCommand = new RunDockerCommand()
-                .withVolumeForRootKeys(rootKeysVolume)
-                .withVolumeForResponse(responseVolume)
-                .withRequestId(requestID)
-                .withDryRun()
-                .withActionRun(toRun);
-        assertEquals(String.format(RUN_IMAGE, rootKeysVolume, responseVolume, requestID, toRun), runImageCommand.toCMD());
-    }
-
-    @Test
-    public void testCreateEMRClusterCommand() {
-        RunDockerCommand createEMRClusterCommand = new RunDockerCommand()
-                .withVolumeForRootKeys(rootKeysVolume)
-                .withVolumeForResponse(responseVolume)
-                .withRequestId(requestID)
-                .withConfServiceBaseName(confServiceBaseName)
-                .withEmrInstanceCount(emrInstanceCount)
-                .withEmrInstanceType(emrInstanceType)
-                .withEmrVersion(emrVersion)
-                .withEc2Role(ec2Role)
-                .withServiceRole(serviceRole)
-                .withNotebookName(notebookName)
-                .withEdgeUserName(edgeUserName)
-                .withEdgeSubnetCidr(edgeSubnetCidr)
-                .withAwsRegion(credsRegion)
-                .withConfKeyName(credsKeyName)
-                .withActionCreate(toCreate);
-
-        assertEquals(
-                String.format(
-                        CREATE_EMR_CLUSTER,
-                        rootKeysVolume,
-                        responseVolume,
-                        requestID,
-                        confServiceBaseName,
-                        emrInstanceCount,
-                        emrInstanceType,
-                        emrVersion,
-                        ec2Role,
-                        serviceRole,
-                        notebookName,
-                        edgeUserName,
-                        edgeSubnetCidr,
-                        credsRegion,
-                        credsKeyName,
-                        toCreate
-                ),
-                createEMRClusterCommand.toCMD()
-        );
-    }
-
-    @Test
-    public void testTerminateEmrCluster() {
-        RunDockerCommand terminateEMRClusterCommand = new RunDockerCommand()
-                .withVolumeForRootKeys(rootKeysVolume)
-                .withVolumeForResponse(responseVolume)
-                .withRequestId(requestID)
-                .withConfServiceBaseName(confServiceBaseName)
-                .withEdgeUserName(edgeUserName)
-                .withEmrClusterName(emrClusterName)
-                .withAwsRegion(credsRegion)
-                .withConfKeyName(credsKeyName)
-                .withActionTerminate(toTerminate);
-
-        assertEquals(
-                String.format(
-                        TERMINATE_EMR_CLUSTER,
-                        rootKeysVolume,
-                        responseVolume,
-                        requestID,
-                        confServiceBaseName,
-                        edgeUserName,
-                        emrClusterName,
-                        credsRegion,
-                        credsKeyName,
-                        toTerminate
-                ),
-                terminateEMRClusterCommand.toCMD()
-        );
-    }
-
-    @Test
-    public void testCreateExploratoryEnvironment() {
-        RunDockerCommand createExploratoryEnvironmentCommand = new RunDockerCommand()
-                .withVolumeForRootKeys(rootKeysVolume)
-                .withVolumeForResponse(responseVolume)
-                .withRequestId(requestID)
-                .withConfServiceBaseName(confServiceBaseName)
-                .withAwsRegion(credsRegion)
-                .withConfKeyName(credsKeyName)
-                .withNotebookUserName(notebookUserName)
-                .withNotebookSubnetCidr(notebookSubnetCidr)
-                .withAwsSecurityGroupsIds(credsSecurityGroupsIds)
-                .withActionCreate(toCreate);
-
-        assertEquals(
-                String.format(
-                        CREATE_EXPLORATORY_ENVIRONMENT,
-                        rootKeysVolume,
-                        responseVolume,
-                        requestID,
-                        confServiceBaseName,
-                        credsRegion,
-                        credsKeyName,
-                        notebookUserName,
-                        notebookSubnetCidr,
-                        credsSecurityGroupsIds,
-                        toCreate
-                ),
-                createExploratoryEnvironmentCommand.toCMD()
-        );
-    }
-
-    @Test
-    public void testTerminateExploratoryEnvironment() {
-        RunDockerCommand terminateExploratoryEnvironmentCommand = new RunDockerCommand()
-                .withVolumeForRootKeys(rootKeysVolume)
-                .withVolumeForResponse(responseVolume)
-                .withRequestId(requestID)
-                .withConfServiceBaseName(confServiceBaseName)
-                .withAwsRegion(credsRegion)
-                .withConfKeyName(credsKeyName)
-                .withNotebookUserName(notebookUserName)
-                .withNotebookInstanceName(notebookInstanceName)
-                .withActionTerminate(toTerminate);
-
-        assertEquals(
-                String.format(
-                        TERMINATE_EXPLORATORY_ENVIRONMENT,
-                        rootKeysVolume,
-                        responseVolume,
-                        requestID,
-                        confServiceBaseName,
-                        credsRegion,
-                        credsKeyName,
-                        notebookUserName,
-                        notebookInstanceName,
-                        toTerminate
-                ),
-                terminateExploratoryEnvironmentCommand.toCMD()
-        );
-    }
-
-    @Test
-    public void testStopExploratoryEnvironment() {
-        RunDockerCommand stopExploratoryEnvironmentCommand = new RunDockerCommand()
-                .withVolumeForRootKeys(rootKeysVolume)
-                .withVolumeForResponse(responseVolume)
-                .withRequestId(requestID)
-                .withConfServiceBaseName(confServiceBaseName)
-                .withAwsRegion(credsRegion)
-                .withConfKeyName(credsKeyName)
-                .withNotebookUserName(notebookUserName)
-                .withNotebookInstanceName(notebookInstanceName)
-                .withActionStop(toStop);
-
-        assertEquals(
-                String.format(
-                        STOP_EXPLORATORY_ENVIRONMENT,
-                        rootKeysVolume,
-                        responseVolume,
-                        requestID,
-                        confServiceBaseName,
-                        credsRegion,
-                        credsKeyName,
-                        notebookUserName,
-                        notebookInstanceName,
-                        toStop
-                ),
-                stopExploratoryEnvironmentCommand.toCMD()
-        );
-    }
-
-}
diff --git a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/response/folderlistener/FolderListenerTest.java b/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/response/folderlistener/FolderListenerTest.java
deleted file mode 100644
index 1ba3aab..0000000
--- a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/response/folderlistener/FolderListenerTest.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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.core.response.folderlistener;
-
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.util.ServiceUtils;
-import org.junit.Test;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.concurrent.ExecutionException;
-
-import static org.junit.Assert.assertEquals;
-
-public class FolderListenerTest {
-	private final long maxWaitTimeoutMillis = 30000;
-	
-	private final long timeoutMillis = 2000;
-
-	private final long fileLengthCheckDelay = 1000;
-	
-	private boolean handleResult = true;
-	
-	public class FileHandler implements FileHandlerCallback {
-		private final String uuid;
-
-		public FileHandler(String uuid) {
-			this.uuid = uuid;
-		}
-
-		@Override
-		public String getUUID() {
-			return uuid;
-		}
-
-		@Override
-		public boolean checkUUID(String uuid) {
-			return this.uuid.equals(uuid);
-		}
-
-		@Override
-		public boolean handle(String fileName, byte[] content) throws Exception {
-			if (!handleResult) {
-				throw new Exception("Test exception");
-			}
-			return handleResult;
-		}
-
-		@Override
-		public void handleError(String errorMessage) {
-			System.out.println("handleError called for UUID " + getUUID());
-		}
-
-		@Override
-		public String getUser() {
-			return null;
-		}
-	}
-
-	private String getFileName(String uuid) {
-		return "FolderListenerTest_" + uuid + ".json";
-	}
-
-	private String getDirectory() {
-		return ServiceUtils.getUserDir();
-	}
-	
-	private void removeFile(String uuid) throws IOException {
-		File file = new File(getDirectory(), getFileName(uuid));
-		if ( file.exists() ) {
-			file.delete();
-		}
-	}
-
-	private void createFile(String uuid) throws IOException {
-		File file = new File(getDirectory(), getFileName(uuid));
-		removeFile(uuid);
-		FileWriter f = new FileWriter(file);
-		
-		f.write("test");
-		f.flush();
-		f.close();
-	}
-	
-	
-	private void processFile(WatchItem item) throws InterruptedException, IOException {
-		long expiredTime = System.currentTimeMillis() + maxWaitTimeoutMillis;
-		while (!FolderListener.getListeners().isEmpty() &&
-				!FolderListener.getListeners().get(0).isListen()) {
-			if (expiredTime < System.currentTimeMillis()) {
-				throw new InterruptedException("Timeout has been expired");
-			}
-			Thread.sleep(100);
-		}
-
-		expiredTime = System.currentTimeMillis() + maxWaitTimeoutMillis;
-		while (item.getFuture() == null) {
-			if (expiredTime < System.currentTimeMillis()) {
-				throw new InterruptedException("Timeout has been expired");
-			}
-			Thread.sleep(100);
-		}
-	}
-	
-	@Test
-	public void listen() throws InterruptedException, ExecutionException, IOException {
-		Integer uuid = 1;
-		FileHandlerCallback fHandler;
-		WatchItem item;
-		
-		handleResult = false;
-		fHandler = new FileHandler(uuid.toString());
-		item = FolderListener.listen(getDirectory(), fHandler, timeoutMillis, fileLengthCheckDelay, null);
-		FolderListener listener = FolderListener.getListeners().get(0);
-		assertEquals(false, listener.isListen());
-		assertEquals(true, listener.isAlive());
-		System.out.println("TEST process FALSE");
-		
-		uuid = 2;
-		createFile(uuid.toString());
-		fHandler = new FileHandler(uuid.toString());
-		item = FolderListener.listen(getDirectory(), fHandler, timeoutMillis, fileLengthCheckDelay, null);
-		processFile(item);
-		assertEquals(true, listener.isListen());
-		assertEquals(false, item.getFutureResultSync());
-		assertEquals(false, item.getFutureResult());
-
-		System.out.println("TEST process TRUE");
-		uuid = 3;
-		handleResult = true;
-		createFile(uuid.toString());
-		fHandler = new FileHandler(uuid.toString());
-		item = FolderListener.listen(getDirectory(), fHandler, timeoutMillis, fileLengthCheckDelay, null);
-		processFile(item);
-		assertEquals(true, item.getFutureResultSync());
-		assertEquals(true, item.getFutureResult());
-		
-		System.out.println("TEST process with out listen");
-		uuid = 4;
-		createFile(uuid.toString());
-		fHandler = new FileHandler(uuid.toString());
-		item = FolderListener.listen(getDirectory(), fHandler, timeoutMillis, fileLengthCheckDelay, getFileName(uuid
-				.toString()), null);
-		
-		long expiredTime = System.currentTimeMillis() + maxWaitTimeoutMillis;
-		while (item.getFuture() == null) {
-			if (expiredTime < System.currentTimeMillis()) {
-				throw new InterruptedException("Timeout has been expired");
-			}
-			Thread.sleep(100);
-		}
-		assertEquals(true, item.getFutureResultSync());
-		assertEquals(true, item.getFutureResult());
-
-		FolderListener.terminateAll();
-		expiredTime = System.currentTimeMillis() + maxWaitTimeoutMillis;
-		while (FolderListener.getListeners().size() > 0) {
-			if (expiredTime < System.currentTimeMillis()) {
-				throw new InterruptedException("Timeout has been expired");
-			}
-			Thread.sleep(100);
-		}
-
-		System.out.println("All listen tests passed");
-
-	
-		for (int i = 1; i <= uuid; i++) {
-			removeFile(String.valueOf(i));
-		}
-	}
-
-}
diff --git a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/response/folderlistener/WatchItemListTest.java b/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/response/folderlistener/WatchItemListTest.java
deleted file mode 100644
index 780df37..0000000
--- a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/response/folderlistener/WatchItemListTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.core.response.folderlistener;
-
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.response.folderlistener.WatchItem.ItemStatus;
-import org.junit.Test;
-
-import java.util.concurrent.ExecutionException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-public class WatchItemListTest {
-
-	private static final String UUID = "123";
-
-	private final FileHandlerCallback fHandler = new FileHandler(UUID);
-
-	private final long timeoutMillis = 1000;
-
-	private final long fileLengthCheckDelay = 10000;
-
-	public class FileHandler implements FileHandlerCallback {
-		private final String uuid;
-
-		public FileHandler(String uuid) {
-			this.uuid = uuid;
-		}
-
-		@Override
-		public String getUUID() {
-			return uuid;
-		}
-
-		@Override
-		public boolean checkUUID(String uuid) {
-			return this.uuid.equals(uuid);
-		}
-
-		@Override
-		public boolean handle(String fileName, byte[] content) throws Exception {
-			return true;
-		}
-
-		@Override
-		public void handleError(String errorMessage) {
-			System.out.println("handleError called for UUID " + getUUID());
-		}
-
-		@Override
-		public String getUser() {
-			return null;
-		}
-	}
-
-
-	private String getDirectory() {
-		return "./";
-	}
-
-	private String getFileName() {
-		return UUID + ".json";
-	}
-
-	@Test
-	public void checkGetters() {
-		WatchItemList items = new WatchItemList(getDirectory(), null);
-
-		assertEquals(0, items.size());
-
-		items.append(fHandler, timeoutMillis, fileLengthCheckDelay);
-		assertEquals(1, items.size());
-
-		WatchItem item = items.get(0);
-		assertNotNull(item);
-		assertEquals(0, items.getIndex(UUID));
-		assertEquals(item, items.getItem(getFileName()));
-		items.remove(0);
-		assertEquals(0, items.size());
-	}
-
-
-	@Test
-	public void processItem() throws InterruptedException, ExecutionException {
-		WatchItemList items = new WatchItemList(getDirectory(), null);
-		items.append(fHandler, timeoutMillis, fileLengthCheckDelay);
-
-		WatchItem item = items.get(0);
-
-		assertEquals(false, items.processItem(item));
-
-		item.setFileName(getFileName());
-		assertEquals(true, items.processItem(item));
-
-		assertEquals(ItemStatus.INPROGRESS, item.getStatus());
-		item.getFutureResultSync();
-	}
-
-	@Test
-	public void processItemAll() throws InterruptedException, ExecutionException {
-		WatchItemList items = new WatchItemList(getDirectory(), null);
-		items.append(fHandler, timeoutMillis, fileLengthCheckDelay);
-
-		WatchItem item = items.get(0);
-
-		assertEquals(0, items.processItemAll());
-
-		item.setFileName(getFileName());
-		assertEquals(1, items.processItemAll());
-
-		assertEquals(ItemStatus.INPROGRESS, item.getStatus());
-		item.getFutureResultSync();
-	}
-
-}
diff --git a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/response/folderlistener/WatchItemTest.java b/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/response/folderlistener/WatchItemTest.java
deleted file mode 100644
index 33798b9..0000000
--- a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/response/folderlistener/WatchItemTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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.core.response.folderlistener;
-
-import com.epam.dlab.backendapi.core.FileHandlerCallback;
-import com.epam.dlab.backendapi.core.response.folderlistener.WatchItem.ItemStatus;
-import io.dropwizard.util.Duration;
-import org.junit.Test;
-
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-import static org.junit.Assert.assertEquals;
-
-public class WatchItemTest {
-
-	private static final String UUID = "123";
-
-	private final FileHandlerCallback fHandler = new FileHandler(UUID);
-
-	private final long timeoutMillis = 1000;
-
-	private final long fileLengthCheckDelay = 10000;
-
-	public class FileHandler implements FileHandlerCallback {
-		private final String uuid;
-
-		public FileHandler(String uuid) {
-			this.uuid = uuid;
-		}
-
-		@Override
-		public String getUUID() {
-			return uuid;
-		}
-
-		@Override
-		public boolean checkUUID(String uuid) {
-			return this.uuid.equals(uuid);
-		}
-
-		@Override
-		public boolean handle(String fileName, byte[] content) throws Exception {
-			return true;
-		}
-
-		@Override
-		public void handleError(String errorMessage) {
-			System.out.println("handleError called for UUID " + getUUID());
-		}
-
-		@Override
-		public String getUser() {
-			return null;
-		}
-	}
-
-	
-	private WatchItem getWatchItem() {
-		return new WatchItem(fHandler, timeoutMillis, fileLengthCheckDelay);
-	}
-
-	private String getFileName() {
-		return UUID + ".json";
-	}
-
-	private String getDirectory() {
-		return "./";
-	}
-
-	private AsyncFileHandler getSupplier(WatchItem item) {
-		return new AsyncFileHandler(item.getFileName(), getDirectory(), item.getFileHandlerCallback(),
-				Duration.milliseconds(item.getFileLengthCheckDelay()));
-	}
-	
-	@Test
-	public void isExpired() {
-		WatchItem item;
-
-		item = new WatchItem(fHandler, -1, fileLengthCheckDelay);
-		assertEquals(true, item.isExpired());
-
-		item = getWatchItem();
-		assertEquals(false, item.isExpired());
-	}
-
-	@Test
-	public void status() throws InterruptedException, ExecutionException {
-		WatchItem item;
-
-		item = new WatchItem(fHandler, -1, fileLengthCheckDelay);
-		assertEquals(ItemStatus.TIMEOUT_EXPIRED, item.getStatus());
-
-		item.setFileName(getFileName());
-		assertEquals(ItemStatus.FILE_CAPTURED, item.getStatus());
-
-		item = getWatchItem();
-		assertEquals(ItemStatus.WAIT_FOR_FILE, item.getStatus());
-
-		item.setFileName(getFileName());
-		assertEquals(ItemStatus.FILE_CAPTURED, item.getStatus());
-
-		item.setFuture(CompletableFuture.supplyAsync(getSupplier(item)));
-		assertEquals(ItemStatus.INPROGRESS, item.getStatus());
-		
-		assertEquals(null, item.getFutureResult());
-		item.getFutureResultSync();
-		
-		assertEquals(ItemStatus.IS_DONE, item.getStatus());
-
-		item.setFuture(CompletableFuture.supplyAsync(getSupplier(item)));
-		item.getFuture().cancel(false);
-		assertEquals(ItemStatus.IS_CANCELED, item.getStatus());
-		
-		//IS_INTERRUPTED, IS_FAILED
-	}
-	
-	@Test
-	public void futureResult() throws InterruptedException, ExecutionException {
-		WatchItem item = getWatchItem();
-		
-		item.setFileName(getFileName());
-		item.setFuture(CompletableFuture.supplyAsync(getSupplier(item)));
-		
-		assertEquals(false, item.getFutureResultSync());
-		assertEquals(false, item.getFutureResult());
-	}
-}
diff --git a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/response/handlers/dao/FileSystemCallbackHandlerDaoTest.java b/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/response/handlers/dao/FileSystemCallbackHandlerDaoTest.java
deleted file mode 100644
index 0dc3663..0000000
--- a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/core/response/handlers/dao/FileSystemCallbackHandlerDaoTest.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * 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.core.response.handlers.dao;
-
-import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.core.DockerWarmuper;
-import com.epam.dlab.backendapi.core.commands.DockerAction;
-import com.epam.dlab.backendapi.core.response.handlers.LibListCallbackHandler;
-import com.epam.dlab.backendapi.core.response.handlers.PersistentFileHandler;
-import com.epam.dlab.exceptions.DlabException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Matchers;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-
-import static org.junit.Assert.*;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.refEq;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class FileSystemCallbackHandlerDaoTest {
-
-	@Mock
-	private ObjectMapper mapper;
-	@Mock
-	private ProvisioningServiceApplicationConfiguration configuration;
-	@Mock
-	private CallbackHandlerDao dao;
-	@InjectMocks
-	private FileSystemCallbackHandlerDao fileSystemCallbackHandlerDao;
-
-	@Rule
-	public TemporaryFolder folder = new TemporaryFolder();
-	@Rule
-	public ExpectedException expectedException = ExpectedException.none();
-
-	@Before
-	public void createHandlersFolder() throws IOException {
-		folder.newFolder("opt", "handlers");
-	}
-
-
-	@Test
-	public void upsert() throws IOException {
-		final String handlersFolders = getHandlersFolder();
-		when(configuration.getHandlerDirectory()).thenReturn(handlersFolders);
-		when(mapper.writeValueAsBytes(any())).thenReturn("{'test': 'test'}".getBytes());
-		final PersistentFileHandler persistentFileHandler =
-				new PersistentFileHandler(new LibListCallbackHandler(null,
-						DockerAction.LIB_LIST, "uuid", "test", "das"), 1L, "/opt/test");
-
-		fileSystemCallbackHandlerDao.upsert(persistentFileHandler);
-
-		verify(configuration, times(2)).getHandlerDirectory();
-		verify(mapper).writeValueAsBytes(refEq(persistentFileHandler));
-		assertTrue(new File(handlersFolders + File.separator + "LibListCallbackHandler_uuid.json").exists());
-		verifyNoMoreInteractions(mapper, configuration, dao);
-	}
-
-	@Test
-	public void upsertTwoSimilarHandlers() throws IOException {
-		final String handlersFolders = getHandlersFolder();
-		when(configuration.getHandlerDirectory()).thenReturn(handlersFolders);
-		when(mapper.writeValueAsBytes(any())).thenReturn("{'test': 'test'}".getBytes());
-		final PersistentFileHandler persistentFileHandler1 = new PersistentFileHandler(new DockerWarmuper()
-				.new DockerFileHandlerCallback("sameUUID"), 1L, "/opt/test");
-		final PersistentFileHandler persistentFileHandler2 =
-				new PersistentFileHandler(new LibListCallbackHandler(null,
-						DockerAction.LIB_LIST, "sameUUID", "test", "das1"), 1L, "/opt/test");
-		final PersistentFileHandler persistentFileHandler3 =
-				new PersistentFileHandler(new LibListCallbackHandler(null,
-						DockerAction.LIB_LIST, "anotherUUID", "test", "das2"), 1L, "/opt/test");
-
-
-		fileSystemCallbackHandlerDao.upsert(persistentFileHandler1);
-		fileSystemCallbackHandlerDao.upsert(persistentFileHandler2);
-		fileSystemCallbackHandlerDao.upsert(persistentFileHandler3);
-
-		verify(configuration, times(6)).getHandlerDirectory();
-		verify(mapper).writeValueAsBytes(refEq(persistentFileHandler1));
-		verify(mapper).writeValueAsBytes(refEq(persistentFileHandler2));
-		verify(mapper).writeValueAsBytes(refEq(persistentFileHandler3));
-		assertTrue(new File(handlersFolders + File.separator + "LibListCallbackHandler_sameUUID.json").exists());
-		assertTrue(new File(handlersFolders + File.separator + "LibListCallbackHandler_anotherUUID.json").exists());
-		assertFalse(new File(handlersFolders + File.separator + "DockerFileHandlerCallback_sameUUID.json").exists());
-		verifyNoMoreInteractions(mapper, configuration, dao);
-	}
-
-	@Test
-	public void findAll() throws IOException {
-		final File handler1 = getHandlerFile("test1.json");
-		final File handler2 = getHandlerFile("test2.json");
-		final String handlersFolder = getHandlersFolder();
-
-		when(configuration.getHandlerDirectory()).thenReturn(handlersFolder);
-		final PersistentFileHandler persistentFileHandler1 = new PersistentFileHandler(null, 1L, "/opt");
-		final PersistentFileHandler persistentFileHandler2 = new PersistentFileHandler(null, 2L, "/opt");
-		when(mapper.readValue(any(File.class), Matchers.<Class<PersistentFileHandler>>any())).thenReturn
-				(persistentFileHandler1).thenReturn(persistentFileHandler2);
-		final List<PersistentFileHandler> handlers = fileSystemCallbackHandlerDao.findAll();
-
-		assertEquals(2, handlers.size());
-
-		verify(configuration).getHandlerDirectory();
-		verify(mapper).readValue(handler1, PersistentFileHandler.class);
-		verify(mapper).readValue(handler2, PersistentFileHandler.class);
-		verifyNoMoreInteractions(mapper, dao, configuration);
-	}
-
-	@Test
-	public void findAllWithException() throws IOException {
-		new File(getHandlersFolder()).delete();
-		when(configuration.getHandlerDirectory()).thenReturn(getHandlersFolder());
-		when(mapper.readValue(any(File.class), Matchers.<Class<PersistentFileHandler>>any())).thenThrow(new
-				RuntimeException("Exception"));
-		final List<PersistentFileHandler> handlers = fileSystemCallbackHandlerDao.findAll();
-
-		assertEquals(0, handlers.size());
-
-		verify(configuration).getHandlerDirectory();
-		verifyNoMoreInteractions(mapper, dao, configuration);
-	}
-
-	@Test
-	public void findAllWithOneWrongHandlerFile() throws IOException {
-		final File handler1 = getHandlerFile("test1.json");
-		final File handler2 = getHandlerFile("test2.json");
-		final String handlersFolder = getHandlersFolder();
-
-		final PersistentFileHandler persistentFileHandler1 = new PersistentFileHandler(null, 1L, "/opt");
-
-		when(configuration.getHandlerDirectory()).thenReturn(handlersFolder);
-		when(mapper.readValue(any(File.class), Matchers.<Class<PersistentFileHandler>>any())).thenReturn
-				(persistentFileHandler1).thenThrow(new RuntimeException("Exception"));
-
-		final List<PersistentFileHandler> handlers = fileSystemCallbackHandlerDao.findAll();
-
-		assertEquals(1, handlers.size());
-
-		verify(configuration).getHandlerDirectory();
-		verify(mapper).readValue(handler1, PersistentFileHandler.class);
-		verify(mapper).readValue(handler2, PersistentFileHandler.class);
-		verifyNoMoreInteractions(mapper, dao, configuration);
-	}
-
-	private String getHandlersFolder() {
-		return folder.getRoot().getAbsolutePath() +
-				File.separator + "opt" + File.separator + "handlers";
-	}
-
-	private File getHandlerFile(String handlerFileName) throws IOException {
-		return folder.newFile(File.separator + "opt" + File.separator + "handlers" + File.separator +
-				handlerFileName);
-	}
-
-	@Test
-	public void remove() throws IOException {
-		final File handler = getHandlerFile("test1.json");
-		handler.createNewFile();
-		final String handlersFolder = getHandlersFolder();
-
-		when(configuration.getHandlerDirectory()).thenReturn(handlersFolder);
-		fileSystemCallbackHandlerDao.remove("test1");
-
-		assertFalse(handler.exists());
-
-		verify(configuration).getHandlerDirectory();
-		verifyNoMoreInteractions(configuration, dao, mapper);
-	}
-
-	@Test
-	public void removeWithException() throws IOException {
-		final String handlersFolder = getHandlersFolder();
-
-		when(configuration.getHandlerDirectory()).thenReturn(handlersFolder);
-		expectedException.expect(DlabException.class);
-		fileSystemCallbackHandlerDao.remove("test1.json");
-	}
-}
\ No newline at end of file
diff --git a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/service/RestoreCallbackHandlerServiceImplTest.java b/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/service/RestoreCallbackHandlerServiceImplTest.java
deleted file mode 100644
index aba84c3..0000000
--- a/services/provisioning-service/src/test/java/com/epam/dlab/backendapi/service/RestoreCallbackHandlerServiceImplTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.core.response.folderlistener.FolderListenerExecutor;
-import com.epam.dlab.backendapi.core.response.handlers.PersistentFileHandler;
-import com.epam.dlab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
-import com.epam.dlab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
-import io.dropwizard.util.Duration;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.Arrays;
-
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class RestoreCallbackHandlerServiceImplTest {
-
-	@Mock
-	private CallbackHandlerDao dao;
-	@Mock
-	private FolderListenerExecutor folderListenerExecutor;
-	@InjectMocks
-	private RestoreCallbackHandlerServiceImpl restoreCallbackHandlerService;
-
-	@Test
-	public void start() throws Exception {
-
-		final PersistentFileHandler handler1 = new PersistentFileHandler(null, 1L, "test");
-		final PersistentFileHandler handler2 = new PersistentFileHandler(null, 2L, "test1");
-		when(dao.findAll()).thenReturn(Arrays.asList(handler1, handler2));
-
-		restoreCallbackHandlerService.start();
-
-		verify(dao).findAll();
-		verify(folderListenerExecutor).start(handler1.getDirectory(), Duration.milliseconds(handler1.getTimeout()),
-				handler1.getHandler());
-		verify(folderListenerExecutor).start(handler2.getDirectory(), Duration.milliseconds(handler2.getTimeout()),
-				handler2.getHandler());
-		verifyNoMoreInteractions(dao, folderListenerExecutor);
-	}
-}
\ No newline at end of file
diff --git a/services/provisioning-service/src/test/java/com/epam/dlab/rest/client/RESTServiceMock.java b/services/provisioning-service/src/test/java/com/epam/dlab/rest/client/RESTServiceMock.java
deleted file mode 100644
index 3341d4f..0000000
--- a/services/provisioning-service/src/test/java/com/epam/dlab/rest/client/RESTServiceMock.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.rest.client;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RESTServiceMock extends RESTService {
-
-    private final static Logger LOG = LoggerFactory.getLogger(RESTService.class);
-
-    @Override
-    public <T> T post(String path, Object parameter, Class<T> clazz) {
-        LOG.debug("REST POST {},\n object {},\n response class {}", path, parameter, clazz.getName());
-        try {
-			return (T) clazz.newInstance();
-		} catch (InstantiationException e) {
-			e.printStackTrace();
-		} catch (IllegalAccessException e) {
-			e.printStackTrace();
-		}
-        return null;
-    }
-}
diff --git a/services/self-service/entrypoint.sh b/services/self-service/entrypoint.sh
index c3c47fd..f1303fd 100644
--- a/services/self-service/entrypoint.sh
+++ b/services/self-service/entrypoint.sh
@@ -53,4 +53,4 @@
 /usr/bin/openssl pkcs12 -export -in /root/step-certs/tls.crt -inkey /root/step-certs/tls.key -name ssn -out ssn.p12 -password pass:${SSN_KEYSTORE_PASSWORD}
 /usr/bin/keytool -importkeystore -srckeystore ssn.p12 -srcstoretype PKCS12 -alias ssn -destkeystore /root/keys/ssn.keystore.jks -deststorepass "${SSN_KEYSTORE_PASSWORD}" -srcstorepass "${SSN_KEYSTORE_PASSWORD}"
 /usr/bin/keytool -keystore /root/keys/ssn.keystore.jks -alias step-ca -import -file /root/step-certs/ca.crt  -deststorepass "${SSN_KEYSTORE_PASSWORD}" -srcstorepass "${SSN_KEYSTORE_PASSWORD}" -noprompt
-/usr/bin/java -Xmx2048M -jar -Duser.timezone=UTC -Dfile.encoding=UTF-8 -DDLAB_CONF_DIR=/root/ /root/self-service-2.4.jar server /root/self-service.yml
\ No newline at end of file
+/usr/bin/java -Xmx2048M -jar -Duser.timezone=UTC -Dfile.encoding=UTF-8 -DDATALAB_CONF_DIR=/root/ /root/self-service-2.4.jar server /root/self-service.yml
\ No newline at end of file
diff --git a/services/self-service/pom.xml b/services/self-service/pom.xml
index b5c075b..1d0a3ef 100644
--- a/services/self-service/pom.xml
+++ b/services/self-service/pom.xml
@@ -21,8 +21,8 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
-        <groupId>com.epam.dlab</groupId>
-        <artifactId>dlab</artifactId>
+        <groupId>com.epam.datalab</groupId>
+        <artifactId>datalab</artifactId>
         <version>1.0</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
@@ -56,7 +56,7 @@
             <version>2.1.0</version>
         </dependency>
         <dependency>
-            <groupId>com.epam.dlab</groupId>
+            <groupId>com.epam.datalab</groupId>
             <artifactId>common</artifactId>
         </dependency>
         <dependency>
@@ -118,25 +118,25 @@
             <version>${com.jcraft.jsch.version}</version>
         </dependency>
         <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>dlab-model</artifactId>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>datalab-model</artifactId>
             <version>${project.parent.version}</version>
         </dependency>
         <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>dlab-utils</artifactId>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>datalab-utils</artifactId>
             <version>${project.parent.version}</version>
         </dependency>
 
         <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>dlab-webapp-common</artifactId>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>datalab-webapp-common</artifactId>
             <version>${project.parent.version}</version>
         </dependency>
 
         <dependency>
-            <groupId>com.epam.dlab</groupId>
-            <artifactId>dlab-mongo-migration</artifactId>
+            <groupId>com.epam.datalab</groupId>
+            <artifactId>datalab-mongo-migration</artifactId>
             <version>${project.parent.version}</version>
         </dependency>
 
@@ -230,12 +230,12 @@
                                         implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                                 <transformer
                                         implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
-                                    <mainClass>com.epam.dlab.backendapi.SelfServiceApplication</mainClass>
+                                    <mainClass>com.epam.datalab.backendapi.SelfServiceApplication</mainClass>
                                     <manifestEntries>
                                         <Created-By>&lt;EPAM&gt; Systems</Created-By>
-                                        <Name>com/epam/dlab</Name>
-                                        <Implementation-Title>DLab Self-Service</Implementation-Title>
-                                        <DLab-Version>${dlab.version}</DLab-Version>
+                                        <Name>com/epam/datalab</Name>
+                                        <Implementation-Title>DataLab Self-Service</Implementation-Title>
+                                        <DataLab-Version>${datalab.version}</DataLab-Version>
                                         <Implementation-Vendor>&lt;EPAM&gt; Systems</Implementation-Vendor>
                                         <Build-Time>${maven.build.timestamp}</Build-Time>
                                         <Build-OS>${os.name}</Build-OS>
@@ -256,18 +256,18 @@
                         <exclude>**/*Configuration.*</exclude>
                         <exclude>**/*Module.*</exclude>
                         <exclude>**/*Form.*</exclude>
-                        <exclude>com/epam/dlab/dto/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/auth/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/conf/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/domain/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/dropwizard/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/healthcheck/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/modules/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/resources/dto/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/roles/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/servlet/guacamole/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/util/**/*</exclude>
-                        <exclude>com/epam/dlab/backendapi/validation/**/*</exclude>
+                        <exclude>com/epam/datalab/dto/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/auth/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/conf/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/domain/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/dropwizard/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/healthcheck/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/modules/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/resources/dto/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/roles/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/servlet/guacamole/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/util/**/*</exclude>
+                        <exclude>com/epam/datalab/backendapi/validation/**/*</exclude>
                     </excludes>
                 </configuration>
             </plugin>
@@ -280,7 +280,7 @@
                     <outputPath>${project.build.directory}/classes/webapp/dist/assets</outputPath>
                     <outputFormat>JSONANDYAML</outputFormat>
                     <resourcePackages>
-                        <package>com.epam.dlab.backendapi.resources</package>
+                        <package>com.epam.datalab.backendapi.resources</package>
                     </resourcePackages>
                     <prettyPrint>TRUE</prettyPrint>
                 </configuration>
diff --git a/services/self-service/self-service.yml b/services/self-service/self-service.yml
index de7dbc8..033b78f 100644
--- a/services/self-service/self-service.yml
+++ b/services/self-service/self-service.yml
@@ -43,9 +43,9 @@
 # Timeout for check the status of environment via provisioning service
 checkEnvStatusTimeout: 5m
 
-# Restrict access to DLab features using roles policy
+# Restrict access to DataLab features using roles policy
 rolePolicyEnabled: true
-# Default access to DLab features using roles policy
+# Default access to DataLab features using roles policy
 roleDefaultAccess: false
 
 # Set to true to enable the scheduler of billing report.
@@ -56,7 +56,7 @@
   <#if DEV_MODE == "true">
 billingConfFile: ${sys['user.dir']}/../billing/billing.yml
 <#else>
-billingConfFile: ${DLAB_CONF_DIR}/billing.yml
+billingConfFile: ${DATA_LAB_CONF_DIR}/billing.yml
 </#if>
 
 ssnInstanceSize: <SSN_INSTANCE_SIZE>
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/SelfServiceApplication.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/SelfServiceApplication.java
new file mode 100644
index 0000000..0b8a414
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/SelfServiceApplication.java
@@ -0,0 +1,217 @@
+/*
+ * 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.datalab.backendapi;
+
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.IndexCreator;
+import com.epam.datalab.backendapi.domain.ExploratoryLibCache;
+import com.epam.datalab.backendapi.dropwizard.bundles.DatalabKeycloakBundle;
+import com.epam.datalab.backendapi.dropwizard.listeners.MongoStartupListener;
+import com.epam.datalab.backendapi.dropwizard.listeners.RestoreHandlerStartupListener;
+import com.epam.datalab.backendapi.healthcheck.MongoHealthCheck;
+import com.epam.datalab.backendapi.modules.ModuleFactory;
+import com.epam.datalab.backendapi.resources.ApplicationSettingResource;
+import com.epam.datalab.backendapi.resources.AuditResource;
+import com.epam.datalab.backendapi.resources.BackupResource;
+import com.epam.datalab.backendapi.resources.EndpointResource;
+import com.epam.datalab.backendapi.resources.EnvironmentResource;
+import com.epam.datalab.backendapi.resources.ExploratoryResource;
+import com.epam.datalab.backendapi.resources.GitCredsResource;
+import com.epam.datalab.backendapi.resources.ImageExploratoryResource;
+import com.epam.datalab.backendapi.resources.InfrastructureInfoResource;
+import com.epam.datalab.backendapi.resources.InfrastructureTemplateResource;
+import com.epam.datalab.backendapi.resources.KeycloakResource;
+import com.epam.datalab.backendapi.resources.LibExploratoryResource;
+import com.epam.datalab.backendapi.resources.ProjectResource;
+import com.epam.datalab.backendapi.resources.SchedulerJobResource;
+import com.epam.datalab.backendapi.resources.SystemInfoResource;
+import com.epam.datalab.backendapi.resources.UserGroupResource;
+import com.epam.datalab.backendapi.resources.UserRoleResource;
+import com.epam.datalab.backendapi.resources.UserSettingsResource;
+import com.epam.datalab.backendapi.resources.callback.BackupCallback;
+import com.epam.datalab.backendapi.resources.callback.CheckInactivityCallback;
+import com.epam.datalab.backendapi.resources.callback.ComputationalCallback;
+import com.epam.datalab.backendapi.resources.callback.EnvironmentStatusCallback;
+import com.epam.datalab.backendapi.resources.callback.ExploratoryCallback;
+import com.epam.datalab.backendapi.resources.callback.GitCredsCallback;
+import com.epam.datalab.backendapi.resources.callback.ImageCallback;
+import com.epam.datalab.backendapi.resources.callback.LibraryCallback;
+import com.epam.datalab.backendapi.resources.callback.ProjectCallback;
+import com.epam.datalab.backendapi.resources.callback.ReuploadKeyCallback;
+import com.epam.datalab.backendapi.schedulers.internal.ManagedScheduler;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.servlet.guacamole.GuacamoleServlet;
+import com.epam.datalab.cloud.CloudModule;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.migration.mongo.DatalabMongoMigration;
+import com.epam.datalab.mongo.MongoServiceFactory;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.mappers.DatalabValidationExceptionMapper;
+import com.epam.datalab.rest.mappers.JsonProcessingExceptionMapper;
+import com.epam.datalab.rest.mappers.ResourceConflictExceptionMapper;
+import com.epam.datalab.rest.mappers.ResourceNotFoundExceptionMapper;
+import com.epam.datalab.rest.mappers.ResourceQuoteReachedExceptionMapper;
+import com.epam.datalab.rest.mappers.RuntimeExceptionMapper;
+import com.epam.datalab.rest.mappers.ValidationExceptionMapper;
+import com.epam.datalab.util.ServiceUtils;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.name.Names;
+import de.thomaskrille.dropwizard_template_config.TemplateConfigBundle;
+import de.thomaskrille.dropwizard_template_config.TemplateConfigBundleConfiguration;
+import io.dropwizard.Application;
+import io.dropwizard.assets.AssetsBundle;
+import io.dropwizard.forms.MultiPartBundle;
+import io.dropwizard.jersey.setup.JerseyEnvironment;
+import io.dropwizard.jetty.BiDiGzipHandler;
+import io.dropwizard.setup.Bootstrap;
+import io.dropwizard.setup.Environment;
+import lombok.extern.slf4j.Slf4j;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
+
+/**
+ * Self Service based on Dropwizard application.
+ */
+@Slf4j
+public class SelfServiceApplication extends Application<SelfServiceApplicationConfiguration> {
+    public static final String GUACAMOLE_SERVLET_PATH = "/api/tunnel";
+    private static Injector appInjector;
+
+    public static Injector getInjector() {
+        return appInjector;
+    }
+
+    public static void setInjector(Injector injector) {
+        SelfServiceApplication.appInjector = injector;
+    }
+
+    public static void main(String... args) throws Exception {
+        if (ServiceUtils.printAppVersion(SelfServiceApplication.class, args)) {
+            return;
+        }
+        new SelfServiceApplication().run(args);
+    }
+
+    @Override
+    public void initialize(Bootstrap<SelfServiceApplicationConfiguration> bootstrap) {
+        super.initialize(bootstrap);
+        bootstrap.addBundle(new MultiPartBundle());
+        bootstrap.addBundle(new AssetsBundle("/webapp/dist", "/", "index.html"));
+        bootstrap.addBundle(new TemplateConfigBundle(
+                new TemplateConfigBundleConfiguration().fileIncludePath(ServiceUtils.getConfPath())
+        ));
+
+        bootstrap.addBundle(new DatalabKeycloakBundle());
+    }
+
+    @Override
+    public void run(SelfServiceApplicationConfiguration configuration, Environment environment) {
+
+        CloudModule cloudModule = ModuleFactory.getCloudProviderModule(configuration);
+        Injector injector = Guice.createInjector(ModuleFactory.getModule(configuration, environment), cloudModule);
+        setInjector(injector);
+
+        cloudModule.init(environment, injector);
+        if (configuration.isMongoMigrationEnabled()) {
+            environment.lifecycle().addServerLifecycleListener(server -> applyMongoMigration(configuration));
+        }
+        environment.lifecycle().addServerLifecycleListener(injector.getInstance(MongoStartupListener.class));
+        final RestoreHandlerStartupListener restoreHandlerStartupListener =
+                new RestoreHandlerStartupListener(injector.getInstance(Key.get(RESTService.class,
+                        Names.named(ServiceConsts.PROVISIONING_SERVICE_NAME))), injector.getInstance(EndpointService.class));
+        environment.lifecycle().addServerLifecycleListener(restoreHandlerStartupListener);
+        environment.lifecycle().addServerLifecycleListener(this::disableGzipHandlerForGuacamoleServlet);
+        environment.lifecycle().manage(injector.getInstance(IndexCreator.class));
+        environment.lifecycle().manage(injector.getInstance(ExploratoryLibCache.class));
+        environment.lifecycle().manage(injector.getInstance(ManagedScheduler.class));
+        environment.healthChecks().register(ServiceConsts.MONGO_NAME, injector.getInstance(MongoHealthCheck.class));
+
+        environment.servlets().addServlet("GuacamoleServlet", injector.getInstance(GuacamoleServlet.class))
+                .addMapping(GUACAMOLE_SERVLET_PATH);
+
+
+        JerseyEnvironment jersey = environment.jersey();
+
+        jersey.register(new RuntimeExceptionMapper());
+        jersey.register(new JsonProcessingExceptionMapper());
+        jersey.register(new ResourceConflictExceptionMapper());
+        jersey.register(new ResourceNotFoundExceptionMapper());
+        jersey.register(new DatalabValidationExceptionMapper());
+        jersey.register(new ValidationExceptionMapper());
+        jersey.register(new ResourceQuoteReachedExceptionMapper());
+
+        jersey.register(injector.getInstance(InfrastructureTemplateResource.class));
+        jersey.register(injector.getInstance(InfrastructureInfoResource.class));
+
+        jersey.register(injector.getInstance(EnvironmentStatusCallback.class));
+
+        jersey.register(injector.getInstance(ComputationalCallback.class));
+
+        jersey.register(injector.getInstance(UserSettingsResource.class));
+
+        jersey.register(injector.getInstance(ExploratoryResource.class));
+        jersey.register(injector.getInstance(ExploratoryCallback.class));
+
+        jersey.register(injector.getInstance(LibExploratoryResource.class));
+        jersey.register(injector.getInstance(LibraryCallback.class));
+
+        jersey.register(injector.getInstance(GitCredsResource.class));
+        jersey.register(injector.getInstance(GitCredsCallback.class));
+        jersey.register(injector.getInstance(SchedulerJobResource.class));
+        jersey.register(injector.getInstance(ImageExploratoryResource.class));
+        jersey.register(injector.getInstance(ImageCallback.class));
+        jersey.register(injector.getInstance(BackupResource.class));
+        jersey.register(injector.getInstance(BackupCallback.class));
+        jersey.register(injector.getInstance(EnvironmentResource.class));
+        jersey.register(injector.getInstance(ReuploadKeyCallback.class));
+        jersey.register(injector.getInstance(CheckInactivityCallback.class));
+        jersey.register(injector.getInstance(SystemInfoResource.class));
+        jersey.register(injector.getInstance(UserGroupResource.class));
+        jersey.register(injector.getInstance(UserRoleResource.class));
+        jersey.register(injector.getInstance(ApplicationSettingResource.class));
+        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));
+    }
+
+    private void disableGzipHandlerForGuacamoleServlet(Server server) {
+        Handler handler = server.getHandler();
+        while (handler instanceof HandlerWrapper) {
+            handler = ((HandlerWrapper) handler).getHandler();
+            if (handler instanceof BiDiGzipHandler) {
+                log.debug("Disabling Gzip handler for guacamole servlet");
+                ((BiDiGzipHandler) handler).setExcludedPaths(GUACAMOLE_SERVLET_PATH);
+            }
+        }
+    }
+
+    private void applyMongoMigration(SelfServiceApplicationConfiguration configuration) {
+        final MongoServiceFactory mongoFactory = configuration.getMongoFactory();
+
+        new DatalabMongoMigration(mongoFactory.getHost(), mongoFactory.getPort(), mongoFactory.getUsername(),
+                mongoFactory.getPassword(), mongoFactory.getDatabase()).migrate();
+    }
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/Audit.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/Audit.java
new file mode 100644
index 0000000..dd1ab26
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/Audit.java
@@ -0,0 +1,36 @@
+/*
+ * 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.datalab.backendapi.annotation;
+
+import com.epam.datalab.backendapi.domain.AuditActionEnum;
+import com.epam.datalab.backendapi.domain.AuditResourceTypeEnum;
+
+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();
+
+    AuditResourceTypeEnum type();
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/BudgetLimited.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/BudgetLimited.java
new file mode 100644
index 0000000..eca8061
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/BudgetLimited.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab.backendapi.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used to disallow execution of method that is annotated by this annotation in case when
+ * budget limit in reached. Budget can be specified in self service configuration
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface BudgetLimited {
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/Info.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/Info.java
new file mode 100644
index 0000000..61c7d93
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/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.datalab.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/datalab/backendapi/annotation/Project.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/Project.java
new file mode 100644
index 0000000..304da3c
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/Project.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.datalab.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 Project {
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/ProjectAdmin.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/ProjectAdmin.java
new file mode 100644
index 0000000..a712d0d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/ProjectAdmin.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.datalab.backendapi.annotation;
+
+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 ProjectAdmin {
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/ResourceName.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/ResourceName.java
new file mode 100644
index 0000000..d348bd3
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/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.datalab.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/datalab/backendapi/annotation/User.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/User.java
new file mode 100644
index 0000000..c052e6d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/annotation/User.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.datalab.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 User {
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/auth/KeycloakAuthenticator.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/auth/KeycloakAuthenticator.java
new file mode 100644
index 0000000..944d96d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/auth/KeycloakAuthenticator.java
@@ -0,0 +1,52 @@
+/*
+ * 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.datalab.backendapi.auth;
+
+import com.epam.datalab.auth.UserInfo;
+import de.ahus1.keycloak.dropwizard.AbstractKeycloakAuthenticator;
+import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.representations.AccessToken;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+import static java.util.Collections.emptyList;
+
+public class KeycloakAuthenticator extends AbstractKeycloakAuthenticator<UserInfo> {
+
+    private static final String GROUPS_CLAIM = "groups";
+
+    public KeycloakAuthenticator(KeycloakConfiguration keycloakConfiguration) {
+        super(keycloakConfiguration);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected UserInfo prepareAuthentication(KeycloakSecurityContext keycloakSecurityContext,
+                                             HttpServletRequest httpServletRequest,
+                                             KeycloakConfiguration keycloakConfiguration) {
+        final AccessToken token = keycloakSecurityContext.getToken();
+        final UserInfo userInfo = new UserInfo(token.getPreferredUsername(),
+                keycloakSecurityContext.getTokenString());
+        userInfo.addRoles((List<String>) token.getOtherClaims().getOrDefault(GROUPS_CLAIM, emptyList()));
+        return userInfo;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/auth/SelfServiceSecurityAuthorizer.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/auth/SelfServiceSecurityAuthorizer.java
new file mode 100644
index 0000000..974b2ab
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/auth/SelfServiceSecurityAuthorizer.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab.backendapi.auth;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.roles.RoleType;
+import com.epam.datalab.backendapi.roles.UserRoles;
+import com.google.inject.Singleton;
+import io.dropwizard.auth.Authorizer;
+
+@Singleton
+public class SelfServiceSecurityAuthorizer implements Authorizer<UserInfo> {
+    @Override
+    public boolean authorize(UserInfo principal, String role) {
+        return UserRoles.checkAccess(principal, RoleType.PAGE, role, principal.getRoles());
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/auth/filters/DropwizardBearerTokenFilterImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/auth/filters/DropwizardBearerTokenFilterImpl.java
new file mode 100644
index 0000000..e38eabb
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/auth/filters/DropwizardBearerTokenFilterImpl.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.datalab.backendapi.auth.filters;
+
+import org.keycloak.adapters.AdapterDeploymentContext;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.NodesRegistrationManagement;
+import org.keycloak.jaxrs.JaxrsBearerTokenFilterImpl;
+
+import javax.annotation.Priority;
+import javax.ws.rs.Priorities;
+import javax.ws.rs.container.PreMatching;
+
+@PreMatching
+@Priority(Priorities.AUTHENTICATION)
+public class DropwizardBearerTokenFilterImpl extends JaxrsBearerTokenFilterImpl {
+
+    public DropwizardBearerTokenFilterImpl(KeycloakDeployment keycloakDeployment) {
+        deploymentContext = new AdapterDeploymentContext(keycloakDeployment);
+        nodesRegistrationManagement = new NodesRegistrationManagement();
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/CloudConfiguration.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/CloudConfiguration.java
new file mode 100644
index 0000000..e1e1137
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/CloudConfiguration.java
@@ -0,0 +1,59 @@
+/*
+ * 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.datalab.backendapi.conf;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class CloudConfiguration {
+
+    private final String os;
+    private final String serviceBaseName;
+    private final String edgeInstanceSize;
+    private final String subnetId;
+    private final String region;
+    private final String zone;
+    private final String confTagResourceId;
+    private final String securityGroupIds;
+    private final String ssnInstanceSize;
+    private final String notebookVpcId;
+    private final String notebookSubnetId;
+    private final String confKeyDir;
+    private final String vpcId;
+    private final String azureResourceGroupName;
+    private final String ssnStorageAccountTagName;
+    private final String sharedStorageAccountTagName;
+    private final String datalakeTagName;
+    private final String azureClientId;
+    private final String peeringId;
+    private final String gcpProjectId;
+    @JsonProperty("ldap")
+    private final LdapConfig ldapConfig;
+
+    @Data
+    public static class LdapConfig {
+        private final String host;
+        private final String dn;
+        private final String ou;
+        private final String user;
+        private final String password;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/KeycloakConfiguration.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/KeycloakConfiguration.java
new file mode 100644
index 0000000..a4d79ea
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/KeycloakConfiguration.java
@@ -0,0 +1,27 @@
+/*
+ * 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.datalab.backendapi.conf;
+
+import lombok.Data;
+
+@Data
+public class KeycloakConfiguration extends de.ahus1.keycloak.dropwizard.KeycloakConfiguration {
+    private String redirectUri;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/SelfServiceApplicationConfiguration.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/SelfServiceApplicationConfiguration.java
new file mode 100644
index 0000000..4aaff96
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/SelfServiceApplicationConfiguration.java
@@ -0,0 +1,264 @@
+/*
+ * 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.datalab.backendapi.conf;
+
+import com.epam.datalab.ServiceConfiguration;
+import com.epam.datalab.backendapi.domain.SchedulerConfigurationData;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.rest.client.RESTServiceFactory;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.dropwizard.client.JerseyClientConfiguration;
+import io.dropwizard.util.Duration;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import javax.validation.Valid;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import java.util.Map;
+
+/**
+ * Configuration for Self Service.
+ */
+public class SelfServiceApplicationConfiguration extends ServiceConfiguration {
+
+    @Min(value = 2)
+    @JsonProperty
+    private int minEmrInstanceCount;
+
+    @Max(value = 1000)
+    @JsonProperty
+    private int maxEmrInstanceCount;
+
+    @Min(value = 10)
+    @JsonProperty
+    private int minEmrSpotInstanceBidPct;
+
+    @Max(value = 95)
+    @JsonProperty
+    private int maxEmrSpotInstanceBidPct;
+
+    @Min(value = 2)
+    @JsonProperty
+    private int minSparkInstanceCount;
+
+    @Max(value = 1000)
+    @JsonProperty
+    private int maxSparkInstanceCount;
+
+    @JsonProperty
+    private String ssnInstanceSize;
+
+    @JsonProperty
+    private boolean rolePolicyEnabled = false;
+
+    @JsonProperty
+    private boolean roleDefaultAccess = false;
+
+    @JsonProperty
+    private Duration checkEnvStatusTimeout = Duration.minutes(10);
+
+    @JsonProperty
+    private boolean billingSchedulerEnabled = false;
+
+    @JsonProperty
+    private boolean auditEnabled = false;
+
+    @NotEmpty
+    @JsonProperty
+    private String billingConfFile;
+    @JsonProperty
+    private int minInstanceCount;
+    @JsonProperty
+    private int maxInstanceCount;
+    @JsonProperty
+    private int minDataprocPreemptibleCount;
+    @JsonProperty
+    private int maxUserNameLength;
+    @JsonProperty
+    private boolean gcpOuauth2AuthenticationEnabled;
+    @JsonProperty
+    private boolean mongoMigrationEnabled;
+    @JsonProperty
+    private int privateKeySize = 2048;
+    @Valid
+    @NotNull
+    private Map<String, SchedulerConfigurationData> schedulers;
+
+
+    @Valid
+    @NotNull
+    @JsonProperty("jerseyClient")
+    private JerseyClientConfiguration jerseyClient = new JerseyClientConfiguration();
+
+    @Valid
+    @NotNull
+    @JsonProperty(ServiceConsts.MAVEN_SEARCH_API)
+    private RESTServiceFactory mavenApiFactory;
+
+    @Valid
+    @NotNull
+    private Map<String, String> guacamole;
+
+    private String serviceBaseName;
+    private String os;
+
+    private KeycloakConfiguration keycloakConfiguration = new KeycloakConfiguration();
+
+    public Map<String, String> getGuacamole() {
+        return guacamole;
+    }
+
+    public String getGuacamoleHost() {
+        return guacamole.get("serverHost");
+    }
+
+    public Integer getGuacamolePort() {
+        return Integer.valueOf(guacamole.get("serverPort"));
+    }
+
+    public JerseyClientConfiguration getJerseyClientConfiguration() {
+        return jerseyClient;
+    }
+
+    public Map<String, SchedulerConfigurationData> getSchedulers() {
+        return schedulers;
+    }
+
+    public boolean isGcpOuauth2AuthenticationEnabled() {
+        return gcpOuauth2AuthenticationEnabled;
+    }
+
+    /**
+     * Returns the minimum number of slave EMR instances than could be created.
+     */
+    public int getMinEmrInstanceCount() {
+        return minEmrInstanceCount;
+    }
+
+    /**
+     * Returns the maximum number of slave EMR instances than could be created.
+     */
+    public int getMaxEmrInstanceCount() {
+        return maxEmrInstanceCount;
+    }
+
+    /**
+     * Returns the timeout for check the status of environment via provisioning service.
+     */
+    public Duration getCheckEnvStatusTimeout() {
+        return checkEnvStatusTimeout;
+    }
+
+    public int getMinEmrSpotInstanceBidPct() {
+        return minEmrSpotInstanceBidPct;
+    }
+
+    public int getMaxEmrSpotInstanceBidPct() {
+        return maxEmrSpotInstanceBidPct;
+    }
+
+    public int getMinSparkInstanceCount() {
+        return minSparkInstanceCount;
+    }
+
+    public int getMaxSparkInstanceCount() {
+        return maxSparkInstanceCount;
+    }
+
+    /**
+     * Return the <b>true</b> if using roles policy to DataLab features.
+     */
+    public boolean isRolePolicyEnabled() {
+        return rolePolicyEnabled;
+    }
+
+    /**
+     * Return the default access to DataLab features using roles policy.
+     */
+    public boolean getRoleDefaultAccess() {
+        return roleDefaultAccess;
+    }
+
+
+    /**
+     * Return the <b>true</b> if the billing scheduler is enabled.
+     */
+    public boolean isBillingSchedulerEnabled() {
+        return billingSchedulerEnabled;
+    }
+
+    public boolean isAuditEnabled() {
+        return auditEnabled;
+    }
+
+    /**
+     * Return the default access to DataLab features using roles policy.
+     */
+    public String getBillingConfFile() {
+        return billingConfFile;
+    }
+
+
+    public int getMinInstanceCount() {
+        return minInstanceCount;
+    }
+
+    public int getMaxInstanceCount() {
+        return maxInstanceCount;
+    }
+
+    public int getMinDataprocPreemptibleCount() {
+        return minDataprocPreemptibleCount;
+    }
+
+    public int getMaxUserNameLength() {
+        return maxUserNameLength;
+    }
+
+    public int getPrivateKeySize() {
+        return privateKeySize;
+    }
+
+    public String getSsnInstanceSize() {
+        return ssnInstanceSize;
+    }
+
+    public boolean isMongoMigrationEnabled() {
+        return mongoMigrationEnabled;
+    }
+
+    @NotNull
+    public RESTServiceFactory getMavenApiFactory() {
+        return mavenApiFactory;
+    }
+
+    public KeycloakConfiguration getKeycloakConfiguration() {
+        return keycloakConfiguration;
+    }
+
+    public String getServiceBaseName() {
+        return serviceBaseName;
+    }
+
+    public String getOs() {
+        return os;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAO.java
new file mode 100644
index 0000000..ae840fb
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAO.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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.domain.AuditDTO;
+import com.epam.datalab.backendapi.domain.AuditPaginationDTO;
+
+import java.util.List;
+
+public interface AuditDAO {
+    void save(AuditDTO audit);
+
+    List<AuditPaginationDTO> getAudit(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd, int pageNumber, int pageSize);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAOImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAOImpl.java
new file mode 100644
index 0000000..34c14a2
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAOImpl.java
@@ -0,0 +1,172 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.domain.AuditDTO;
+import com.epam.datalab.backendapi.domain.AuditPaginationDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.mongodb.client.model.Facet;
+import com.mongodb.client.model.Filters;
+import com.mongodb.client.model.Sorts;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import static com.epam.datalab.backendapi.dao.ComputationalDAO.PROJECT;
+import static com.mongodb.client.model.Aggregates.count;
+import static com.mongodb.client.model.Aggregates.facet;
+import static com.mongodb.client.model.Aggregates.group;
+import static com.mongodb.client.model.Aggregates.limit;
+import static com.mongodb.client.model.Aggregates.match;
+import static com.mongodb.client.model.Aggregates.skip;
+import static com.mongodb.client.model.Aggregates.sort;
+import static com.mongodb.client.model.Filters.gte;
+import static com.mongodb.client.model.Filters.in;
+import static com.mongodb.client.model.Filters.lte;
+
+public class AuditDAOImpl extends BaseDAO implements AuditDAO {
+    private static final String AUDIT_COLLECTION = "audit";
+    private static final String RESOURCE_NAME_FIELD = "resourceName";
+    private static final String RESOURCE_TYPE_FIELD = "type";
+    private static final String TIMESTAMP_FIELD = "timestamp";
+    private static final String COUNT_FIELD = "count";
+    private static final String AUDIT_FACET = "auditFacet";
+    private static final String TOTAL_COUNT_FACET = "totalCountFacet";
+    private static final String RESOURCE_NAME_FACET = "resourceNameFacet";
+    private static final String USER_FACET = "userFacet";
+    private static final String PROJECT_FACET = "projectFacet";
+    private static final String RESOURCE_TYPE_FACET = "typeFacet";
+
+    @Override
+    public void save(AuditDTO audit) {
+        insertOne(AUDIT_COLLECTION, audit);
+    }
+
+    @Override
+    public List<AuditPaginationDTO> getAudit(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd,
+                                             int pageNumber, int pageSize) {
+        List<Bson> valuesPipeline = new ArrayList<>();
+        List<Bson> countPipeline = new ArrayList<>();
+        List<Bson> matchCriteria = matchCriteria(users, projects, resourceNames, resourceTypes, dateStart, dateEnd);
+        if (!matchCriteria.isEmpty()) {
+            Bson match = match(Filters.and(matchCriteria));
+            valuesPipeline.add(match);
+            countPipeline.add(match);
+        }
+        countPipeline.add(count());
+        valuesPipeline.add(sortCriteria());
+        valuesPipeline.addAll(Arrays.asList(skip(pageSize * (pageNumber - 1)), limit(pageSize)));
+
+        List<Bson> userFilter = Collections.singletonList(group(getGroupingFields(USER)));
+        List<Bson> projectFilter = Collections.singletonList(group(getGroupingFields(PROJECT)));
+        List<Bson> resourceNameFilter = Collections.singletonList(group(getGroupingFields(RESOURCE_NAME_FIELD)));
+        List<Bson> resourceTypeFilter = Collections.singletonList(group(getGroupingFields(RESOURCE_TYPE_FIELD)));
+
+        List<Bson> facets = Collections.singletonList(facet(new Facet(AUDIT_FACET, valuesPipeline), new Facet(TOTAL_COUNT_FACET, countPipeline),
+                new Facet(RESOURCE_NAME_FACET, resourceNameFilter), new Facet(USER_FACET, userFilter), new Facet(PROJECT_FACET, projectFilter),
+                new Facet(RESOURCE_TYPE_FACET, resourceTypeFilter)));
+        return StreamSupport.stream(aggregate(AUDIT_COLLECTION, facets).spliterator(), false)
+                .map(this::toAuditPaginationDTO)
+                .collect(Collectors.toList());
+    }
+
+    private List<Bson> matchCriteria(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd) {
+        List<Bson> searchCriteria = new ArrayList<>();
+        inCriteria(searchCriteria, users, USER);
+        inCriteria(searchCriteria, projects, PROJECT);
+        inCriteria(searchCriteria, resourceNames, RESOURCE_NAME_FIELD);
+        inCriteria(searchCriteria, resourceTypes, RESOURCE_TYPE_FIELD);
+        if (StringUtils.isNotEmpty(dateStart)) {
+            Instant from = getInstant(dateStart);
+            Date date = new Date(from.toEpochMilli());
+            searchCriteria.add(gte(TIMESTAMP_FIELD, date));
+        }
+        if (StringUtils.isNotEmpty(dateEnd)) {
+            Instant to = getInstant(dateEnd).plus(1, ChronoUnit.DAYS);
+            Date date = new Date(to.toEpochMilli());
+            searchCriteria.add(lte(TIMESTAMP_FIELD, date));
+        }
+        return searchCriteria;
+    }
+
+    private Bson sortCriteria() {
+        return sort(Sorts.descending(TIMESTAMP_FIELD));
+    }
+
+    private AuditPaginationDTO toAuditPaginationDTO(Document document) {
+        List<Document> countDocuments = (List<Document>) document.get(TOTAL_COUNT_FACET);
+        final int count = countDocuments.isEmpty() ? 0 : countDocuments.get(0).getInteger(COUNT_FIELD);
+        Set<String> userFilter = getFilter(document, USER_FACET, USER);
+        Set<String> projectFilter = getFilter(document, PROJECT_FACET, PROJECT);
+        Set<String> resourceNameFilter = getFilter(document, RESOURCE_NAME_FACET, RESOURCE_NAME_FIELD);
+        Set<String> resourceTypeFilter = getFilter(document, RESOURCE_TYPE_FACET, RESOURCE_TYPE_FIELD);
+        List<AuditDTO> auditDTOs = (List<AuditDTO>) document.get(AUDIT_FACET);
+        return AuditPaginationDTO.builder()
+                .totalPageCount(count)
+                .audit(auditDTOs)
+                .userFilter(userFilter)
+                .resourceNameFilter(resourceNameFilter)
+                .resourceTypeFilter(resourceTypeFilter)
+                .projectFilter(projectFilter)
+                .build();
+    }
+
+    private Set<String> getFilter(Document document, String facet, String field) {
+        return ((List<Document>) document.get(facet))
+                .stream()
+                .map(d -> (Document) d.get(ID))
+                .map(d -> d.getString(field))
+                .collect(Collectors.toSet());
+    }
+
+    private Instant getInstant(String dateStart) {
+        Instant from;
+        try {
+            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+            simpleDateFormat.setTimeZone(TimeZone.getTimeZone(ZoneOffset.UTC));
+            from = simpleDateFormat.parse(dateStart).toInstant();
+        } catch (ParseException e) {
+            throw new DatalabException(String.format("Cannot parse %s", dateStart), e);
+        }
+        return from;
+    }
+
+    private void inCriteria(List<Bson> searchCriteria, List<String> users, String user) {
+        if (CollectionUtils.isNotEmpty(users)) {
+            searchCriteria.add(in(user, users));
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BackupDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BackupDAO.java
new file mode 100644
index 0000000..6aca851
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BackupDAO.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.resources.dto.BackupInfoRecord;
+import com.epam.datalab.dto.backup.EnvBackupDTO;
+import com.epam.datalab.dto.backup.EnvBackupStatus;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface BackupDAO {
+    void createOrUpdate(EnvBackupDTO dto, String user, EnvBackupStatus status);
+
+    List<BackupInfoRecord> getBackups(String userName);
+
+    Optional<BackupInfoRecord> getBackup(String userName, String id);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BackupDAOImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BackupDAOImpl.java
new file mode 100644
index 0000000..3bbfd6e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BackupDAOImpl.java
@@ -0,0 +1,65 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.resources.dto.BackupInfoRecord;
+import com.epam.datalab.dto.backup.EnvBackupDTO;
+import com.epam.datalab.dto.backup.EnvBackupStatus;
+import com.google.inject.Singleton;
+import org.bson.Document;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+import static com.epam.datalab.backendapi.dao.MongoCollections.REQUEST_ID;
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.eq;
+
+@Singleton
+public class BackupDAOImpl extends BaseDAO implements BackupDAO {
+    @Override
+    public void createOrUpdate(EnvBackupDTO dto, String user, EnvBackupStatus status) {
+        final Document idField = backupId(user, dto.getId());
+        final Document backupDocument = convertToBson(dto)
+                .append(STATUS, status.name())
+                .append(ERROR_MESSAGE, status.message())
+                .append(TIMESTAMP, new Date())
+                .append(ID, idField);
+        updateOne(MongoCollections.BACKUPS,
+                and(eq(ID, idField), eq(REQUEST_ID, dto.getId())),
+                new Document(SET, backupDocument), true);
+    }
+
+    @Override
+    public List<BackupInfoRecord> getBackups(String userName) {
+        return find(MongoCollections.BACKUPS, eq(String.format("%s.%s", ID, USER), userName), BackupInfoRecord.class);
+    }
+
+    @Override
+    public Optional<BackupInfoRecord> getBackup(String userName, String id) {
+        return findOne(MongoCollections.BACKUPS, eq(ID, backupId(userName, id)), BackupInfoRecord.class);
+    }
+
+    private Document backupId(String user, String id) {
+        return new Document(USER, user).append(REQUEST_ID, id);
+    }
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BaseBillingDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BaseBillingDAO.java
new file mode 100644
index 0000000..cb40eff
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BaseBillingDAO.java
@@ -0,0 +1,252 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.domain.BillingReportLine;
+import com.epam.datalab.backendapi.resources.dto.BillingFilter;
+import com.epam.datalab.dto.billing.BillingResourceType;
+import com.google.inject.Inject;
+import com.mongodb.client.model.Aggregates;
+import com.mongodb.client.model.Filters;
+import com.mongodb.client.model.Sorts;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import static com.epam.datalab.backendapi.dao.MongoCollections.BILLING;
+import static com.mongodb.client.model.Accumulators.max;
+import static com.mongodb.client.model.Accumulators.min;
+import static com.mongodb.client.model.Accumulators.sum;
+import static com.mongodb.client.model.Aggregates.group;
+import static com.mongodb.client.model.Aggregates.match;
+import static com.mongodb.client.model.Aggregates.sort;
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.gte;
+import static com.mongodb.client.model.Filters.in;
+import static com.mongodb.client.model.Filters.lte;
+import static com.mongodb.client.model.Filters.regex;
+import static java.time.temporal.TemporalAdjusters.firstDayOfMonth;
+import static java.time.temporal.TemporalAdjusters.lastDayOfMonth;
+import static java.util.Collections.singletonList;
+
+@Slf4j
+public class BaseBillingDAO extends BaseDAO implements BillingDAO {
+    private static final int ONE_HUNDRED = 100;
+    private static final String COST_FIELD = "$cost";
+    private static final String TOTAL_FIELD_NAME = "total";
+    private static final String PROJECT = "project";
+    private static final String APPLICATION = "application";
+    private static final String USAGE_DATE = "usageDate";
+    private static final String USER = "user";
+    private static final String RESOURCE_TYPE = "resource_type";
+    private static final String DATALAB_ID = "datalabId";
+    private static final String FROM = "from";
+    private static final String TO = "to";
+    private static final String PRODUCT = "product";
+    private static final String CURRENCY = "currency";
+    private static final String COST = "cost";
+    private static final String RESOURCE_NAME = "resource_name";
+    private static final String ENDPOINT = "endpoint";
+    private static final String SHAPE = "shape";
+    private static final String EXPLORATORY = "exploratoryName";
+
+    @Inject
+    protected SettingsDAO settings;
+    @Inject
+    private UserSettingsDAO userSettingsDAO;
+    @Inject
+    private ProjectDAO projectDAO;
+
+    @Override
+    public Double getTotalCost() {
+        return aggregateBillingData(singletonList(group(null, sum(TOTAL_FIELD_NAME, COST_FIELD))));
+    }
+
+    @Override
+    public Double getUserCost(String user) {
+        final List<Bson> pipeline = Arrays.asList(match(eq(USER, user)),
+                group(null, sum(TOTAL_FIELD_NAME, COST_FIELD)));
+        return aggregateBillingData(pipeline);
+    }
+
+    @Override
+    public Double getOverallProjectCost(String project) {
+        final List<Bson> pipeline = Arrays.asList(match(eq(PROJECT, project)),
+                group(null, sum(TOTAL_FIELD_NAME, COST_FIELD)));
+        return aggregateBillingData(pipeline);
+    }
+
+    @Override
+    public Double getMonthlyProjectCost(String project, LocalDate date) {
+        final List<Bson> pipeline = Arrays.asList(match(
+                and(
+                        eq(PROJECT, project),
+                        gte(USAGE_DATE, date.with(firstDayOfMonth()).toString()),
+                        lte(USAGE_DATE, date.with(lastDayOfMonth()).toString()))
+                ),
+                group(null, sum(TOTAL_FIELD_NAME, COST_FIELD)));
+        return aggregateBillingData(pipeline);
+    }
+
+    @Override
+    public int getBillingQuoteUsed() {
+        return toPercentage(() -> settings.getMaxBudget(), getTotalCost());
+    }
+
+    @Override
+    public int getBillingUserQuoteUsed(String user) {
+        return toPercentage(() -> userSettingsDAO.getAllowedBudget(user), getUserCost(user));
+    }
+
+    @Override
+    public boolean isBillingQuoteReached() {
+        return getBillingQuoteUsed() >= ONE_HUNDRED;
+    }
+
+    @Override
+    public boolean isUserQuoteReached(String user) {
+        final Double userCost = getUserCost(user);
+        return userSettingsDAO.getAllowedBudget(user)
+                .filter(allowedBudget -> userCost.intValue() != 0 && allowedBudget <= userCost)
+                .isPresent();
+    }
+
+    @Override
+    public List<BillingReportLine> findBillingData(String project, String endpoint, List<String> resourceNames) {
+        return find(BILLING, and(eq(PROJECT, project), eq(ENDPOINT, endpoint), in(RESOURCE_NAME, resourceNames)), BillingReportLine.class);
+    }
+
+    public List<BillingReportLine> aggregateBillingData(BillingFilter filter) {
+        List<Bson> pipeline = new ArrayList<>();
+        List<Bson> matchCriteria = matchCriteria(filter);
+        if (!matchCriteria.isEmpty()) {
+            pipeline.add(Aggregates.match(Filters.and(matchCriteria)));
+        }
+        pipeline.add(groupCriteria());
+        pipeline.add(usageDateSort());
+        return StreamSupport.stream(getCollection(BILLING).aggregate(pipeline).spliterator(), false)
+                .map(this::toBillingReport)
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public void deleteByUsageDate(String application, String usageDate) {
+        deleteMany(BILLING, and(eq(APPLICATION, application), eq(USAGE_DATE, usageDate)));
+    }
+
+    @Override
+    public void deleteByUsageDateRegex(String application, String usageDate) {
+        deleteMany(BILLING, and(eq(APPLICATION, application), regex(USAGE_DATE, "^" + usageDate)));
+    }
+
+    @Override
+    public void save(List<BillingReportLine> billingData) {
+        if (CollectionUtils.isNotEmpty(billingData)) {
+            insertMany(BILLING, new ArrayList<>(billingData));
+        }
+    }
+
+    private Integer toPercentage(Supplier<Optional<Integer>> allowedBudget, Double totalCost) {
+        return allowedBudget.get()
+                .map(userBudget -> (totalCost * ONE_HUNDRED) / userBudget)
+                .map(Double::intValue)
+                .orElse(BigDecimal.ZERO.intValue());
+    }
+
+    private Double aggregateBillingData(List<Bson> pipeline) {
+        return Optional.ofNullable(aggregate(BILLING, pipeline).first())
+                .map(d -> d.getDouble(TOTAL_FIELD_NAME))
+                .orElse(BigDecimal.ZERO.doubleValue());
+    }
+
+    private Bson usageDateSort() {
+        return sort(Sorts.descending(USAGE_DATE));
+    }
+
+    private Bson groupCriteria() {
+        return group(getGroupingFields(USER, DATALAB_ID, RESOURCE_TYPE, RESOURCE_NAME, PROJECT, PRODUCT, CURRENCY, SHAPE, EXPLORATORY),
+                sum(COST, "$" + COST),
+                min(FROM, "$" + FROM),
+                max(TO, "$" + TO));
+    }
+
+    private List<Bson> matchCriteria(BillingFilter filter) {
+        List<Bson> searchCriteria = new ArrayList<>();
+
+        if (CollectionUtils.isNotEmpty(filter.getUsers())) {
+            searchCriteria.add(in(USER, filter.getUsers()));
+        }
+        if (CollectionUtils.isNotEmpty(filter.getResourceTypes())) {
+            searchCriteria.add(in(RESOURCE_TYPE, filter.getResourceTypes()));
+        }
+        if (StringUtils.isNotEmpty(filter.getDatalabId())) {
+            searchCriteria.add(regex(DATALAB_ID, filter.getDatalabId(), "i"));
+        }
+        if (StringUtils.isNotEmpty(filter.getDateStart())) {
+            searchCriteria.add(gte(USAGE_DATE, filter.getDateStart()));
+        }
+        if (StringUtils.isNotEmpty(filter.getDateEnd())) {
+            searchCriteria.add(lte(USAGE_DATE, filter.getDateEnd()));
+        }
+        if (CollectionUtils.isNotEmpty(filter.getProjects())) {
+            searchCriteria.add(in(PROJECT, filter.getProjects()));
+        }
+        if (CollectionUtils.isNotEmpty(filter.getProducts())) {
+            searchCriteria.add(in(PRODUCT, filter.getProducts()));
+        }
+        if (CollectionUtils.isNotEmpty(filter.getShapes())) {
+            searchCriteria.add(regex(SHAPE, "(" + String.join("|", filter.getShapes()) + ")"));
+        }
+
+        return searchCriteria;
+    }
+
+    private BillingReportLine toBillingReport(Document d) {
+        Document id = (Document) d.get("_id");
+        return BillingReportLine.builder()
+                .datalabId(id.getString(DATALAB_ID))
+                .project(id.getString(PROJECT))
+                .resourceName(id.getString(RESOURCE_NAME))
+                .exploratoryName(id.getString(EXPLORATORY))
+                .shape(id.getString(SHAPE))
+                .user(id.getString(USER))
+                .product(id.getString(PRODUCT))
+                .resourceType(Optional.ofNullable(id.getString(RESOURCE_TYPE)).map(BillingResourceType::valueOf).orElse(null))
+                .usageDateFrom(d.getDate(FROM).toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
+                .usageDateTo(d.getDate(TO).toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
+                .cost(BigDecimal.valueOf(d.getDouble(COST)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue())
+                .currency(id.getString(CURRENCY))
+                .build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BaseDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BaseDAO.java
new file mode 100644
index 0000000..4ddc152
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BaseDAO.java
@@ -0,0 +1,526 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.mongo.MongoService;
+import com.epam.datalab.util.mongo.modules.IsoDateModule;
+import com.epam.datalab.util.mongo.modules.JavaPrimitiveModule;
+import com.epam.datalab.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;
+import com.mongodb.client.AggregateIterable;
+import com.mongodb.client.FindIterable;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoCursor;
+import com.mongodb.client.MongoIterable;
+import com.mongodb.client.model.UpdateOptions;
+import com.mongodb.client.result.DeleteResult;
+import com.mongodb.client.result.UpdateResult;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.exists;
+import static com.mongodb.client.model.Filters.ne;
+
+/**
+ * Implements the base API for Mongo database.
+ */
+public class BaseDAO {
+
+    public static final String ID = "_id";
+    public static final String USER = "user";
+    public static final String STATUS = "status";
+    public static final String ERROR_MESSAGE = "error_message";
+    protected static final String INSTANCE_ID = "instance_id";
+    protected static final String EDGE_STATUS = "edge_status";
+    protected static final String ADD_TO_SET = "$addToSet";
+    protected static final String UNSET_OPERATOR = "$unset";
+    static final String FIELD_SET_DELIMETER = ".$.";
+    static final String SET = "$set";
+    static final String TIMESTAMP = "timestamp";
+    static final String REUPLOAD_KEY_REQUIRED = "reupload_key_required";
+    private static final Logger LOGGER = LoggerFactory.getLogger(BaseDAO.class);
+    private static final String INSERT_ERROR_MESSAGE = "Insert to Mongo DB fails: ";
+    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());
+    private static final String PULL = "$pull";
+    private static final String PULL_ALL = "$pullAll";
+    private static final String EACH = "$each";
+    private static final String ELEMENT_AT_OPERATOR = "$arrayElemAt";
+
+    @Inject
+    protected MongoService mongoService;
+
+    /**
+     * Return <b>true</b> if collection exists.
+     *
+     * @param name collection name.
+     */
+    boolean collectionExists(String name) {
+        return mongoService.collectionExists(name);
+    }
+
+    /**
+     * Return Mongo collection.
+     *
+     * @param collection collection name.
+     */
+    public MongoCollection<Document> getCollection(String collection) {
+        return mongoService.getCollection(collection);
+    }
+
+    /**
+     * Inserts the document into the collection.
+     *
+     * @param collection collection name.
+     * @param supplier   document.
+     */
+    protected void insertOne(String collection, Supplier<Document> supplier) {
+        insertOne(collection, supplier, generateUUID());
+    }
+
+    /**
+     * Inserts the document into the collection with given the unique id.
+     *
+     * @param collection collection name.
+     * @param document   document.
+     * @param uuid       unique id.
+     */
+    protected void insertOne(String collection, Supplier<Document> document, String uuid) {
+        try {
+            mongoService.getCollection(collection)
+                    .insertOne(document.get()
+                            .append(ID, uuid)
+                            .append(TIMESTAMP, new Date()));
+        } catch (MongoException e) {
+            LOGGER.warn(INSERT_ERROR_MESSAGE + "{}", e.getLocalizedMessage(), e);
+            throw new DatalabException("Insert to Mongo DB failed: " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Serializes the object and inserts into the collection.
+     *
+     * @param collection collection name.
+     * @param object     for inserting to collection.
+     */
+    protected void insertOne(String collection, Object object) {
+        insertOne(collection, object, generateUUID());
+    }
+
+    /**
+     * Serializes the object and inserts into the collection.
+     *
+     * @param collection collection name.
+     * @param object     for inserting to collection.
+     * @param uuid       unique id.
+     */
+    protected void insertOne(String collection, Object object, String uuid) {
+        try {
+            mongoService.getCollection(collection)
+                    .insertOne(convertToBson(object)
+                            .append(ID, uuid)
+                            .append(TIMESTAMP, new Date()));
+        } catch (MongoException e) {
+            LOGGER.warn(INSERT_ERROR_MESSAGE + "{}", e.getLocalizedMessage(), e);
+            throw new DatalabException(INSERT_ERROR_MESSAGE + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Serializes objects and inserts into the collection.
+     *
+     * @param collection collection name.
+     * @param object     for inserting to collection.
+     */
+    protected void insertMany(String collection, List<Object> object) {
+        try {
+            mongoService.getCollection(collection)
+                    .insertMany(convertToBson(object)
+                            .stream()
+                            .peek(o -> {
+                                o.append(ID, generateUUID());
+                                o.append(TIMESTAMP, new Date());
+                            })
+                            .collect(Collectors.toList())
+                    );
+        } catch (MongoException e) {
+            LOGGER.warn(INSERT_ERROR_MESSAGE + "{}", e.getLocalizedMessage(), e);
+            throw new DatalabException(INSERT_ERROR_MESSAGE + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Updates single document in the collection by condition.
+     *
+     * @param collection collection name.
+     * @param condition  condition for search documents in collection.
+     * @param document   document.
+     */
+    protected UpdateResult updateOne(String collection, Bson condition, Bson document) {
+        try {
+            return mongoService.getCollection(collection)
+                    .updateOne(condition, document);
+        } catch (MongoException e) {
+            LOGGER.warn("Update Mongo DB fails: {}", e.getLocalizedMessage(), e);
+            throw new DatalabException("Update to Mongo DB fails: " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Update or insert single document in the collection by condition.
+     *
+     * @param collection collection name.
+     * @param condition  condition for search documents in collection.
+     * @param document   document.
+     * @param isUpsert   if <b>true</b> document will be updated or inserted.
+     */
+    protected void updateOne(String collection, Bson condition, Bson document, boolean isUpsert) {
+        try {
+            if (isUpsert) {
+                mongoService.getCollection(collection).updateOne(condition, document,
+                        new UpdateOptions().upsert(true));
+            } else {
+                mongoService.getCollection(collection).updateOne(condition, document);
+            }
+        } catch (MongoException e) {
+            LOGGER.warn("Upsert Mongo DB fails: {}", e.getLocalizedMessage(), e);
+            throw new DatalabException("Upsert to Mongo DB fails: " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Updates all documents in the collection by condition.
+     *
+     * @param collection collection name.
+     * @param condition  condition for search documents in collection.
+     * @param document   document.
+     */
+    UpdateResult updateMany(String collection, Bson condition, Bson document) {
+        try {
+            return mongoService.getCollection(collection)
+                    .updateMany(condition, document);
+        } catch (MongoException e) {
+            LOGGER.warn("Update Mongo DB fails: {}", e.getLocalizedMessage(), e);
+            throw new DatalabException("Update to Mongo DB fails: " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Removes single document in the collection by condition.
+     *
+     * @param collection collection name.
+     * @param condition  condition for search documents in collection.
+     */
+    protected DeleteResult deleteOne(String collection, Bson condition) {
+        try {
+            return mongoService.getCollection(collection)
+                    .deleteOne(condition);
+        } catch (MongoException e) {
+            LOGGER.warn("Removing document from Mongo DB fails: {}", e.getLocalizedMessage(), e);
+            throw new DatalabException("Removing document from Mongo DB fails: " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Removes many documents in the collection by condition.
+     *
+     * @param collection collection name.
+     * @param condition  condition for search documents in collection.
+     */
+    protected DeleteResult deleteMany(String collection, Bson condition) {
+        try {
+            return mongoService.getCollection(collection)
+                    .deleteMany(condition);
+        } catch (MongoException e) {
+            LOGGER.warn("Removing document from Mongo DB fails: {}", e.getLocalizedMessage(), e);
+            throw new DatalabException("Removing document from Mongo DB fails: " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    /**
+     * Finds and returns all documents from the collection.
+     *
+     * @param collection collection name.
+     */
+    protected FindIterable<Document> find(String collection) {
+        return mongoService.getCollection(collection).find();
+    }
+
+    /**
+     * Finds and returns documents from the collection by condition.
+     *
+     * @param collection collection name.
+     * @param condition  condition for search documents in collection.
+     */
+    protected FindIterable<Document> find(String collection, Bson condition) {
+        return mongoService.getCollection(collection)
+                .find(condition);
+    }
+
+    /**
+     * Finds and returns all documents from the collection converted to resulted type.
+     *
+     * @param collection    collection name.
+     * @param resultedClass type of class for deserialization.
+     */
+    protected <T> List<T> find(String collection, Class<T> resultedClass) {
+        return find(collection)
+                .into(new ArrayList<>())
+                .stream()
+                .map(d -> convertFromDocument(d, resultedClass))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Finds and returns documents from the collection by condition.
+     *
+     * @param collection    collection name.
+     * @param condition     condition for search documents in collection.
+     * @param resultedClass type of class for deserialization.
+     */
+    protected <T> List<T> find(String collection, Bson condition, Class<T> resultedClass) {
+        return mongoService.getCollection(collection)
+                .find(condition)
+                .into(new ArrayList<>())
+                .stream()
+                .map(d -> convertFromDocument(d, resultedClass))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Finds and returns documents with the specified fields from the collection by condition.
+     *
+     * @param collection collection name.
+     * @param condition  condition for search documents in collection.
+     * @param projection document describing the fields in the collection to return.
+     */
+    protected FindIterable<Document> find(String collection, Bson condition, Bson projection) {
+        return mongoService.getCollection(collection)
+                .find(condition)
+                .projection(projection);
+    }
+
+    /**
+     * Aggregates and returns documents according to the specified aggregation pipeline.
+     *
+     * @param collection collection name.
+     * @param pipeline   the aggregate pipeline.
+     */
+    public AggregateIterable<Document> aggregate(String collection, List<? extends Bson> pipeline) {
+        return mongoService.getCollection(collection)
+                .aggregate(pipeline);
+    }
+
+    /**
+     * Checks that the documents iterator have one document only.
+     *
+     * @param documents documents
+     */
+    private Optional<Document> limitOne(MongoIterable<Document> documents) {
+        Document first = documents.first();
+        try (MongoCursor<Document> iterator = documents.iterator()) {
+            if (iterator.hasNext()) {
+                iterator.next();
+                if (iterator.hasNext()) {
+                    throw new DatalabException("too many items found while one is expected");
+                }
+            }
+        }
+        return Optional.ofNullable(first);
+    }
+
+    /**
+     * Finds and returns one document from the collection by condition.
+     *
+     * @param collection collection name.
+     * @param condition  condition for search documents in collection.
+     * @throws DatalabException if documents iterator have more than one document.
+     */
+    protected Optional<Document> findOne(String collection, Bson condition) {
+        FindIterable<Document> found = find(collection, condition);
+        return limitOne(found);
+    }
+
+    /**
+     * Finds and returns one document with the specified fields from the collection by condition.
+     *
+     * @param collection collection name.
+     * @param condition  condition for search documents in collection.
+     * @param projection document describing the fields in the collection to return.
+     * @throws DatalabException if documents iterator have more than one document.
+     */
+    protected Optional<Document> findOne(String collection, Bson condition, Bson projection) {
+        FindIterable<Document> found = find(collection, condition, projection);
+        return limitOne(found);
+    }
+
+    /**
+     * Serializes given object to document and returns it.
+     *
+     * @param object object
+     */
+    Document convertToBson(Object object) {
+        try {
+            return Document.parse(MAPPER.writeValueAsString(object));
+        } catch (IOException e) {
+            throw new DatalabException("error converting to bson", e);
+        }
+    }
+
+    List<Document> convertToBson(List<Object> objects) {
+        return objects
+                .stream()
+                .map(this::convertToBson)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Finds and returns one object as given class from the collection by condition.
+     *
+     * @param collection collection name.
+     * @param condition  condition for search documents in collection.
+     * @param clazz      type of class for deserialization.
+     */
+    protected <T> Optional<T> findOne(String collection, Bson condition, Class<T> clazz) {
+        Optional<Document> doc = findOne(collection, condition);
+        return doc.map(document -> convertFromDocument(document, clazz));
+    }
+
+    /**
+     * Finds and returns one object as given class and with the specified fields from the collection by condition.
+     *
+     * @param collection collection name.
+     * @param condition  condition for search documents in collection.
+     * @param projection document describing the fields in the collection to return.
+     * @param clazz      type of class for deserialization.
+     */
+    protected <T> Optional<T> findOne(String collection, Bson condition, Bson projection, Class<T> clazz) {
+        Optional<Document> doc = findOne(collection, condition, projection);
+        return doc.map(document -> convertFromDocument(document, clazz));
+    }
+
+    /**
+     * Deserializes given document to object and returns it.
+     *
+     * @param document element from database
+     */
+    <T> T convertFromDocument(Document document, Class<T> clazz) {
+        try {
+            String json = document.toJson();
+            return MAPPER.readValue(json, clazz);
+        } catch (IOException e) {
+            throw new DatalabException("error converting from document with id " + document.get(ID), e);
+        }
+    }
+
+    <T> T convertFromDocument(List<Document> documents, TypeReference<T> valueTypeRef) {
+        final String jsonArray = documents.stream()
+                .map(Document::toJson)
+                .collect(Collectors.joining(",", "[", "]"));
+        try {
+            return MAPPER.readValue(jsonArray, valueTypeRef);
+        } catch (IOException e) {
+            throw new DatalabException("error converting array " + jsonArray, e);
+        }
+    }
+
+    protected Document getGroupingFields(String... fieldNames) {
+        Document d = new Document();
+        for (String name : fieldNames) {
+            d.put(name, "$" + name);
+        }
+        return d;
+    }
+
+    protected Stream<Document> stream(Iterable<Document> iterable) {
+        return StreamSupport.stream(iterable.spliterator(), false);
+    }
+
+    List<String> statusList(UserInstanceStatus[] statuses) {
+        return Arrays.stream(statuses).map(UserInstanceStatus::toString).collect(Collectors.toList());
+    }
+
+    List<String> statusList(List<UserInstanceStatus> statuses) {
+        return statuses.stream().map(UserInstanceStatus::toString).collect(Collectors.toList());
+    }
+
+    /**
+     * Returns a unique id.
+     */
+    private String generateUUID() {
+        return UUID.randomUUID().toString();
+    }
+
+    protected BasicDBObject addToSet(String columnName, Set<String> values) {
+        return new BasicDBObject(ADD_TO_SET, new BasicDBObject(columnName, new BasicDBObject(EACH, values)));
+    }
+
+    protected Bson unset(String columnName, String value) {
+        return new BasicDBObject(UNSET_OPERATOR, new BasicDBObject(columnName, value));
+    }
+
+    protected BasicDBObject pull(String columnName, String value) {
+        return new BasicDBObject(PULL, new BasicDBObject(columnName, value));
+    }
+
+    protected BasicDBObject pullAll(String columnName, Set<String> values) {
+        return new BasicDBObject(PULL_ALL, new BasicDBObject(columnName, values));
+    }
+
+    protected Document elementAt(String arrayColumnName, int index) {
+        return new Document(ELEMENT_AT_OPERATOR, Arrays.asList("$" + arrayColumnName, index));
+    }
+
+    protected Document elementAt(Bson bson, int index) {
+        return new Document(ELEMENT_AT_OPERATOR, Arrays.asList(bson, index));
+    }
+
+    protected Bson notNull(String fieldName) {
+        return and(exists(fieldName), ne(fieldName, null));
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BillingDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BillingDAO.java
new file mode 100644
index 0000000..a49ed7b
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/BillingDAO.java
@@ -0,0 +1,53 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.domain.BillingReportLine;
+import com.epam.datalab.backendapi.resources.dto.BillingFilter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+public interface BillingDAO {
+    Double getTotalCost();
+
+    Double getUserCost(String user);
+
+    Double getOverallProjectCost(String project);
+
+    Double getMonthlyProjectCost(String project, LocalDate date);
+
+    int getBillingQuoteUsed();
+
+    int getBillingUserQuoteUsed(String user);
+
+    boolean isBillingQuoteReached();
+
+    boolean isUserQuoteReached(String user);
+
+    List<BillingReportLine> findBillingData(String project, String endpoint, List<String> resourceNames);
+
+    List<BillingReportLine> aggregateBillingData(BillingFilter filter);
+
+    void deleteByUsageDate(String application, String usageDate);
+
+    void deleteByUsageDateRegex(String application, String usageDate);
+
+    void save(List<BillingReportLine> billingData);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ComputationalDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ComputationalDAO.java
new file mode 100644
index 0000000..50c7a02
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ComputationalDAO.java
@@ -0,0 +1,403 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+
+import com.epam.datalab.backendapi.util.DateRemoverUtil;
+import com.epam.datalab.dto.ResourceURL;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.dto.StatusEnvBaseDTO;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.computational.ComputationalStatusDTO;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.exceptions.DatalabException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.mongodb.client.model.Filters;
+import com.mongodb.client.result.UpdateResult;
+import lombok.extern.slf4j.Slf4j;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.COMPUTATIONAL_RESOURCES;
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.UPTIME;
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.exploratoryCondition;
+import static com.epam.datalab.backendapi.dao.MongoCollections.USER_INSTANCES;
+import static com.epam.datalab.backendapi.dao.SchedulerJobDAO.SCHEDULER_DATA;
+import static com.epam.datalab.dto.UserInstanceStatus.TERMINATED;
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.in;
+import static com.mongodb.client.model.Filters.ne;
+import static com.mongodb.client.model.Filters.not;
+import static com.mongodb.client.model.Projections.elemMatch;
+import static com.mongodb.client.model.Projections.excludeId;
+import static com.mongodb.client.model.Projections.fields;
+import static com.mongodb.client.model.Projections.include;
+import static com.mongodb.client.model.Updates.push;
+import static com.mongodb.client.model.Updates.set;
+import static java.util.stream.Collectors.toList;
+
+/**
+ * DAO for user computational resources.
+ */
+@Slf4j
+public class ComputationalDAO extends BaseDAO {
+    static final String COMPUTATIONAL_NAME = "computational_name";
+    static final String COMPUTATIONAL_ID = "computational_id";
+    static final String PROJECT = "project";
+
+    static final String IMAGE = "image";
+    private static final String COMPUTATIONAL_URL = "computational_url";
+    private static final String EXPLORATORY_NAME = "exploratory_name";
+    private static final String COMPUTATIONAL_URL_DESC = "description";
+    private static final String COMPUTATIONAL_URL_URL = "url";
+    private static final String COMPUTATIONAL_LAST_ACTIVITY = "last_activity";
+    private static final String CONFIG = "config";
+
+    private static String computationalFieldFilter(String fieldName) {
+        return COMPUTATIONAL_RESOURCES + FIELD_SET_DELIMETER + fieldName;
+    }
+
+    private static Bson computationalCondition(String user, String project, String exploratoryName, String compName) {
+        return and(eq(USER, user), eq(PROJECT, project), eq(EXPLORATORY_NAME, exploratoryName),
+                eq(COMPUTATIONAL_RESOURCES + "." + COMPUTATIONAL_NAME, compName));
+    }
+
+    /**
+     * Add the user's computational resource for notebook into database.
+     *
+     * @param user             user name.
+     * @param exploratoryName  name of exploratory.
+     * @param project          name of project
+     * @param computationalDTO object of computational resource.
+     * @return <b>true</b> if operation was successful, otherwise <b>false</b>.
+     */
+    public boolean addComputational(String user, String exploratoryName, String project,
+                                    UserComputationalResource computationalDTO) {
+        final UpdateResult updateResult = updateOne(USER_INSTANCES,
+                and(exploratoryCondition(user, exploratoryName, project),
+                        not(elemMatch(COMPUTATIONAL_RESOURCES,
+                                eq(COMPUTATIONAL_NAME, computationalDTO.getComputationalName())))),
+                push(COMPUTATIONAL_RESOURCES, convertToBson(computationalDTO)));
+        return updateResult.getModifiedCount() > 0;
+    }
+
+    /**
+     * Finds and returns the of computational resource.
+     *
+     * @param user              user name.
+     * @param project           project name
+     * @param exploratoryName   the name of exploratory.
+     * @param computationalName name of computational resource.
+     * @throws DatalabException if exception occurs
+     */
+    public UserComputationalResource fetchComputationalFields(String user, String project, String exploratoryName,
+                                                              String computationalName) {
+        Optional<UserInstanceDTO> opt = findOne(USER_INSTANCES,
+                and(exploratoryCondition(user, exploratoryName, project),
+                        Filters.elemMatch(COMPUTATIONAL_RESOURCES, eq(COMPUTATIONAL_NAME, computationalName))),
+                fields(include(COMPUTATIONAL_RESOURCES + ".$"), excludeId()),
+                UserInstanceDTO.class);
+        return opt.map(UserInstanceDTO::getResources)
+                .filter(l -> !l.isEmpty())
+                .map(l -> l.get(0))
+                .orElseThrow(() -> new DatalabException("Computational resource " + computationalName + " for user " + user + " with " +
+                        "exploratory name " + exploratoryName + " not found."));
+    }
+
+    public List<UserComputationalResource> findComputationalResourcesWithStatus(String user, String project, String exploratoryName,
+                                                                                UserInstanceStatus status) {
+        final UserInstanceDTO userInstanceDTO = findOne(USER_INSTANCES,
+                and(exploratoryCondition(user, exploratoryName, project),
+                        elemMatch(COMPUTATIONAL_RESOURCES, eq(STATUS, status.toString()))),
+                fields(include(COMPUTATIONAL_RESOURCES), excludeId()),
+                UserInstanceDTO.class)
+                .orElseThrow(() -> new DatalabException(String.format("Computational resource with status %s for user " +
+                        "%s with exploratory name %s not found.", status, user, exploratoryName)));
+        return userInstanceDTO.getResources()
+                .stream()
+                .filter(computationalResource -> computationalResource.getStatus().equals(status.toString()))
+                .collect(toList());
+    }
+
+    /**
+     * Updates the status of computational resource in Mongo database.
+     *
+     * @param dto object of computational resource status.
+     * @return The result of an update operation.
+     */
+    public UpdateResult updateComputationalStatus(ComputationalStatusDTO dto) {
+        try {
+            Document values = new Document(computationalFieldFilter(STATUS), dto.getStatus());
+            return updateOne(USER_INSTANCES,
+                    and(exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
+                            elemMatch(COMPUTATIONAL_RESOURCES,
+                                    and(eq(COMPUTATIONAL_NAME, dto.getComputationalName()),
+                                            not(eq(STATUS, TERMINATED.toString()))))),
+                    new Document(SET, values));
+        } catch (Exception t) {
+            throw new DatalabException("Could not update computational resource status", t);
+        }
+    }
+
+    /**
+     * Updates the status of exploratory notebooks in Mongo database.
+     *
+     * @param dto object of exploratory status info.
+     * @return The result of an update operation.
+     */
+    public int updateComputationalStatusesForExploratory(StatusEnvBaseDTO<?> dto) {
+        Document values = new Document(computationalFieldFilter(STATUS), dto.getStatus());
+        values.append(computationalFieldFilter(UPTIME), null);
+        int count = 0;
+        UpdateResult result;
+        do {
+            result = updateOne(USER_INSTANCES,
+                    and(exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
+                            elemMatch(COMPUTATIONAL_RESOURCES,
+                                    and(not(eq(STATUS, TERMINATED.toString())),
+                                            not(eq(STATUS, dto.getStatus()))))),
+                    new Document(SET, values));
+            count += result.getModifiedCount();
+        }
+        while (result.getModifiedCount() > 0);
+
+        return count;
+    }
+
+    public void updateComputationalStatusesForExploratory(String user, String project, String exploratoryName,
+                                                          UserInstanceStatus dataengineStatus,
+                                                          UserInstanceStatus dataengineServiceStatus,
+                                                          UserInstanceStatus... excludedStatuses) {
+        updateComputationalResource(user, project, exploratoryName, dataengineStatus,
+                DataEngineType.SPARK_STANDALONE, excludedStatuses);
+        updateComputationalResource(user, project, exploratoryName, dataengineServiceStatus,
+                DataEngineType.CLOUD_SERVICE, excludedStatuses);
+    }
+
+    /**
+     * Updates the status for single computational resource in Mongo database.
+     *
+     * @param user              user name.
+     * @param project           project name
+     * @param exploratoryName   exploratory's name.
+     * @param computationalName name of computational resource.
+     * @param newStatus         new status of computational resource.
+     */
+
+    public void updateStatusForComputationalResource(String user, String project, String exploratoryName,
+                                                     String computationalName, UserInstanceStatus newStatus) {
+        updateComputationalField(user, project, exploratoryName, computationalName, STATUS, newStatus.toString());
+    }
+
+
+    private void updateComputationalResource(String user, String project, String exploratoryName,
+                                             UserInstanceStatus dataengineServiceStatus, DataEngineType cloudService,
+                                             UserInstanceStatus... excludedStatuses) {
+        UpdateResult result;
+        do {
+            result = updateMany(USER_INSTANCES,
+                    computationalFilter(user, project, exploratoryName,
+                            dataengineServiceStatus.toString(), DataEngineType.getDockerImageName(cloudService), excludedStatuses),
+                    new Document(SET,
+                            new Document(computationalFieldFilter(STATUS), dataengineServiceStatus.toString())));
+        } while (result.getModifiedCount() > 0);
+    }
+
+    private Bson computationalFilter(String user, String project, String exploratoryName, String computationalStatus,
+                                     String computationalImage, UserInstanceStatus[] excludedStatuses) {
+        final String[] statuses = Arrays.stream(excludedStatuses)
+                .map(UserInstanceStatus::toString)
+                .toArray(String[]::new);
+        return and(exploratoryCondition(user, exploratoryName, project),
+                elemMatch(COMPUTATIONAL_RESOURCES, and(eq(IMAGE, computationalImage),
+                        not(in(STATUS, statuses)),
+                        not(eq(STATUS, computationalStatus)))));
+    }
+
+    /**
+     * Updates the info of computational resource in Mongo database.
+     *
+     * @param dto object of computational resource status.
+     * @return The result of an update operation.
+     * @throws DatalabException if exception occurs
+     */
+    public UpdateResult updateComputationalFields(ComputationalStatusDTO dto) {
+        try {
+            Document values = new Document(computationalFieldFilter(STATUS), dto.getStatus());
+            if (dto.getUptime() != null) {
+                values.append(computationalFieldFilter(UPTIME), dto.getUptime());
+            }
+            if (dto.getInstanceId() != null) {
+                values.append(computationalFieldFilter(INSTANCE_ID), dto.getInstanceId());
+            }
+            if (null != dto.getErrorMessage()) {
+                values.append(computationalFieldFilter(ERROR_MESSAGE),
+                        DateRemoverUtil.removeDateFormErrorMessage(dto.getErrorMessage()));
+            }
+            if (dto.getComputationalId() != null) {
+                values.append(computationalFieldFilter(COMPUTATIONAL_ID), dto.getComputationalId());
+            }
+            if (dto.getResourceUrl() != null && !dto.getResourceUrl().isEmpty()) {
+                values.append(computationalFieldFilter(COMPUTATIONAL_URL), getResourceUrlData(dto));
+            }
+            if (dto.getLastActivity() != null) {
+                values.append(computationalFieldFilter(COMPUTATIONAL_LAST_ACTIVITY), dto.getLastActivity());
+            }
+            if (dto.getConfig() != null) {
+                values.append(computationalFieldFilter(CONFIG),
+                        dto.getConfig().stream().map(this::convertToBson).collect(toList()));
+            }
+            return updateOne(USER_INSTANCES, and(exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
+                    elemMatch(COMPUTATIONAL_RESOURCES,
+                            and(eq(COMPUTATIONAL_NAME, dto.getComputationalName()),
+                                    not(eq(STATUS, TERMINATED.toString()))))),
+                    new Document(SET, values));
+        } catch (Exception t) {
+            throw new DatalabException("Could not update computational resource status", t);
+        }
+    }
+
+    private List<Map<String, String>> getResourceUrlData(ComputationalStatusDTO dto) {
+        return dto.getResourceUrl().stream()
+                .map(this::toUrlDocument)
+                .collect(toList());
+    }
+
+    private LinkedHashMap<String, String> toUrlDocument(ResourceURL url) {
+        LinkedHashMap<String, String> map = new LinkedHashMap<>();
+        map.put(COMPUTATIONAL_URL_DESC, url.getDescription());
+        map.put(COMPUTATIONAL_URL_URL, url.getUrl());
+        return map;
+    }
+
+    /**
+     * Updates the requirement for reuploading key for single computational resource in Mongo database.
+     *
+     * @param user                user name.
+     * @param project             project name
+     * @param exploratoryName     exploratory's name.
+     * @param computationalName   name of computational resource.
+     * @param reuploadKeyRequired true/false.
+     */
+
+    public void updateReuploadKeyFlagForComputationalResource(String user, String project, String exploratoryName,
+                                                              String computationalName, boolean reuploadKeyRequired) {
+        updateComputationalField(user, project, exploratoryName, computationalName, REUPLOAD_KEY_REQUIRED, reuploadKeyRequired);
+    }
+
+    /**
+     * Returns names of computational resources which status is among existing ones. Also these resources will
+     * have predefined type.
+     *
+     * @param user                  user name.
+     * @param project               project name
+     * @param computationalTypes    type list of computational resource which may contain 'dataengine' and/or
+     *                              'dataengine-service'.
+     * @param exploratoryName       name of exploratory.
+     * @param computationalStatuses statuses of computational resource.
+     * @return list of computational resources' names
+     */
+
+    @SuppressWarnings("unchecked")
+    public List<String> getComputationalResourcesWhereStatusIn(String user, String project,
+                                                               List<DataEngineType> computationalTypes,
+                                                               String exploratoryName,
+                                                               UserInstanceStatus... computationalStatuses) {
+        return stream((List<Document>) find(USER_INSTANCES, exploratoryCondition(user, exploratoryName, project),
+                fields(include(COMPUTATIONAL_RESOURCES))).first().get(COMPUTATIONAL_RESOURCES))
+                .filter(doc ->
+                        statusList(computationalStatuses).contains(doc.getString(STATUS)) &&
+                                computationalTypes.contains(DataEngineType.fromDockerImageName(doc.getString(IMAGE))))
+                .map(doc -> doc.getString(COMPUTATIONAL_NAME)).collect(toList());
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<ClusterConfig> getClusterConfig(String user, String project, String exploratoryName, String computationalName) {
+        return findOne(USER_INSTANCES,
+                and(exploratoryCondition(user, exploratoryName, project),
+                        Filters.elemMatch(COMPUTATIONAL_RESOURCES, and(eq(COMPUTATIONAL_NAME, computationalName),
+                                notNull(CONFIG)))),
+                fields(include(COMPUTATIONAL_RESOURCES + ".$"), excludeId())
+        ).map(d -> ((List<Document>) d.get(COMPUTATIONAL_RESOURCES)).get(0))
+                .map(d -> convertFromDocument((List<Document>) d.get(CONFIG),
+                        new TypeReference<List<ClusterConfig>>() {
+                        }))
+                .orElse(Collections.emptyList());
+    }
+
+    /**
+     * Updates computational resource's field.
+     *
+     * @param user              user name.
+     * @param project           project name
+     * @param exploratoryName   name of exploratory.
+     * @param computationalName name of computational resource.
+     * @param fieldName         computational field's name for updating.
+     * @param fieldValue        computational field's value for updating.
+     */
+
+    private <T> UpdateResult updateComputationalField(String user, String project, String exploratoryName, String computationalName,
+                                                      String fieldName, T fieldValue) {
+        return updateOne(USER_INSTANCES,
+                computationalCondition(user, project, exploratoryName, computationalName),
+                set(computationalFieldFilter(fieldName), fieldValue));
+    }
+
+    public void updateSchedulerSyncFlag(String user, String project, String exploratoryName, boolean syncFlag) {
+        final String syncStartField = SCHEDULER_DATA + ".sync_start_required";
+        UpdateResult result;
+        do {
+
+            result = updateOne(USER_INSTANCES, and(exploratoryCondition(user, exploratoryName, project),
+                    elemMatch(COMPUTATIONAL_RESOURCES, and(ne(SCHEDULER_DATA, null), ne(syncStartField, syncFlag)))),
+                    set(computationalFieldFilter(syncStartField), syncFlag));
+
+        } while (result.getModifiedCount() != 0);
+    }
+
+    public UpdateResult updateSchedulerDataForComputationalResource(String user, String project, String exploratoryName,
+                                                                    String computationalName, SchedulerJobDTO dto) {
+        return updateComputationalField(user, project, exploratoryName, computationalName,
+                SCHEDULER_DATA, Objects.isNull(dto) ? null : convertToBson(dto));
+    }
+
+    public void updateLastActivity(String user, String project, String exploratoryName,
+                                   String computationalName, LocalDateTime lastActivity) {
+        updateOne(USER_INSTANCES,
+                computationalCondition(user, project, exploratoryName, computationalName),
+                set(computationalFieldFilter(COMPUTATIONAL_LAST_ACTIVITY),
+                        Date.from(lastActivity.atZone(ZoneId.systemDefault()).toInstant())));
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/DockerDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/DockerDAO.java
new file mode 100644
index 0000000..1573684
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/DockerDAO.java
@@ -0,0 +1,43 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.exceptions.DatalabException;
+import org.bson.Document;
+
+import static com.epam.datalab.backendapi.dao.MongoCollections.DOCKER_ATTEMPTS;
+
+/**
+ * DAO write attempt of Docker
+ */
+public class DockerDAO extends BaseDAO {
+    public static final String RUN = "run";
+
+    /**
+     * Write the attempt of docker action.
+     *
+     * @param user   user name.
+     * @param action action of docker.
+     * @throws DatalabException may be thrown
+     */
+    public void writeDockerAttempt(String user, String action) {
+        insertOne(DOCKER_ATTEMPTS, () -> new Document(USER, user).append("action", action));
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/EndpointDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/EndpointDAO.java
new file mode 100644
index 0000000..3343d9c
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/EndpointDAO.java
@@ -0,0 +1,53 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * The interface specifies behaviour for objects, which retrieve, update, remove
+ * the endpoints entities from the DataBase, according passed fields, i.e name, url, status.
+ */
+public interface EndpointDAO {
+    List<EndpointDTO> getEndpoints();
+
+    List<EndpointDTO> getEndpointsWithStatus(String status);
+
+    /*** Retrieve the Endpoint entity according required name
+     * @param name - the Endpoint regular title
+     * @return the Optional object
+     */
+    Optional<EndpointDTO> get(String name);
+
+    /*** Retrieve the Endpoint entity according required Endpoint URL
+     * @param url - the Endpoint web address
+     * @return the Optional object
+     */
+    Optional<EndpointDTO> getEndpointWithUrl(String url);
+
+    void create(EndpointDTO endpointDTO);
+
+    void updateEndpointStatus(String name, String status);
+
+    void remove(String name);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/EndpointDAOImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/EndpointDAOImpl.java
new file mode 100644
index 0000000..5b3fedf
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/EndpointDAOImpl.java
@@ -0,0 +1,90 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.regex;
+
+
+public class EndpointDAOImpl extends BaseDAO implements EndpointDAO {
+
+    private static final String ENDPOINTS_COLLECTION = "endpoints";
+    private static final String ENDPOINT_NAME_FIELD = "name";
+    private static final String ENDPOINT_STATUS_FIELD = "status";
+    private static final String ENDPOINT_URL_FIELD = "url";
+
+    @Override
+    public List<EndpointDTO> getEndpoints() {
+        return find(ENDPOINTS_COLLECTION, EndpointDTO.class);
+    }
+
+    @Override
+    public List<EndpointDTO> getEndpointsWithStatus(String status) {
+        return find(ENDPOINTS_COLLECTION, endpointStatusCondition(status), EndpointDTO.class);
+    }
+
+    @Override
+    public Optional<EndpointDTO> getEndpointWithUrl(String url) {
+        return findOne(ENDPOINTS_COLLECTION, endpointUrlCondition(url), EndpointDTO.class);
+    }
+
+    @Override
+    public Optional<EndpointDTO> get(String name) {
+        return findOne(ENDPOINTS_COLLECTION, endpointCondition(name), EndpointDTO.class);
+    }
+
+    @Override
+    public void create(EndpointDTO endpointDTO) {
+        insertOne(ENDPOINTS_COLLECTION, endpointDTO);
+    }
+
+    @Override
+    public void updateEndpointStatus(String name, String status) {
+        final Document updatedFiled = new Document(ENDPOINT_STATUS_FIELD, status);
+        updateOne(ENDPOINTS_COLLECTION, endpointCondition(name), new Document(SET, updatedFiled));
+    }
+
+    @Override
+    public void remove(String name) {
+        deleteOne(ENDPOINTS_COLLECTION, endpointCondition(name));
+    }
+
+    private Bson endpointCondition(String name) {
+        Pattern endPointName = Pattern.compile("^" + name + "$", Pattern.CASE_INSENSITIVE);
+        return regex(ENDPOINT_NAME_FIELD, endPointName);
+    }
+
+    private Bson endpointUrlCondition(String url) {
+        Pattern endPointUrl = Pattern.compile("^" + url + "$", Pattern.CASE_INSENSITIVE);
+        return regex(ENDPOINT_URL_FIELD, endPointUrl);
+    }
+
+    private Bson endpointStatusCondition(String status) {
+        return eq(ENDPOINT_STATUS_FIELD, status);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/EnvDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/EnvDAO.java
new file mode 100644
index 0000000..61317a1
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/EnvDAO.java
@@ -0,0 +1,512 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.SelfServiceApplication;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.resources.aws.ComputationalResourceAws;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.status.EnvResource;
+import com.epam.datalab.dto.status.EnvResourceList;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.model.ResourceType;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.mongodb.client.model.Updates;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.COMPUTATIONAL_RESOURCES;
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.EXPLORATORY_NAME;
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.exploratoryCondition;
+import static com.epam.datalab.backendapi.dao.MongoCollections.USER_EDGE;
+import static com.epam.datalab.backendapi.dao.MongoCollections.USER_INSTANCES;
+import static com.epam.datalab.dto.UserInstanceStatus.CONFIGURING;
+import static com.epam.datalab.dto.UserInstanceStatus.CREATING;
+import static com.epam.datalab.dto.UserInstanceStatus.FAILED;
+import static com.epam.datalab.dto.UserInstanceStatus.RUNNING;
+import static com.epam.datalab.dto.UserInstanceStatus.STARTING;
+import static com.epam.datalab.dto.UserInstanceStatus.STOPPED;
+import static com.epam.datalab.dto.UserInstanceStatus.STOPPING;
+import static com.epam.datalab.dto.UserInstanceStatus.TERMINATED;
+import static com.epam.datalab.dto.UserInstanceStatus.TERMINATING;
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.in;
+import static com.mongodb.client.model.Filters.not;
+import static com.mongodb.client.model.Filters.or;
+import static com.mongodb.client.model.Projections.elemMatch;
+import static com.mongodb.client.model.Projections.excludeId;
+import static com.mongodb.client.model.Projections.fields;
+import static com.mongodb.client.model.Projections.include;
+import static java.util.Objects.nonNull;
+
+/**
+ * DAO for updates of the status of environment resources.
+ */
+@Singleton
+public class EnvDAO extends BaseDAO {
+    private static final Logger LOGGER = LoggerFactory.getLogger(EnvDAO.class);
+
+    private static final String EDGE_PUBLIC_IP = "public_ip";
+    private static final String COMPUTATIONAL_STATUS = COMPUTATIONAL_RESOURCES + "." + STATUS;
+    private static final String COMPUTATIONAL_STATUS_FILTER = COMPUTATIONAL_RESOURCES + FIELD_SET_DELIMETER + STATUS;
+    private static final String COMPUTATIONAL_SPOT = "slave_node_spot";
+    private static final String IMAGE = "image";
+    private static final String PROJECT = "project";
+    private static final String ENDPOINT = "endpoint";
+
+    private static final Bson INCLUDE_EDGE_FIELDS = include(INSTANCE_ID, EDGE_STATUS, EDGE_PUBLIC_IP);
+    private static final Bson INCLUDE_EXP_FIELDS = include(INSTANCE_ID, STATUS, PROJECT, ENDPOINT,
+            COMPUTATIONAL_RESOURCES + "." + INSTANCE_ID, COMPUTATIONAL_RESOURCES + "." + IMAGE, COMPUTATIONAL_STATUS,
+            EXPLORATORY_NAME, COMPUTATIONAL_RESOURCES + "." + ComputationalDAO.COMPUTATIONAL_NAME);
+    private static final Bson INCLUDE_EXP_UPDATE_FIELDS = include(EXPLORATORY_NAME, INSTANCE_ID, STATUS,
+            COMPUTATIONAL_RESOURCES + "." + ComputationalDAO.COMPUTATIONAL_NAME, COMPUTATIONAL_RESOURCES + "." +
+                    INSTANCE_ID,
+            COMPUTATIONAL_STATUS, COMPUTATIONAL_RESOURCES + "." + IMAGE);
+    private static final String COMPUTATIONAL_NAME = "computational_name";
+
+    @Inject
+    private SelfServiceApplicationConfiguration configuration;
+
+    /**
+     * Finds and returns the list of user resources.
+     *
+     * @param user name.
+     */
+    public Map<String, EnvResourceList> findEnvResources(String user) {
+        List<EnvResource> hostList = new ArrayList<>();
+        List<EnvResource> clusterList = new ArrayList<>();
+
+        stream(find(USER_INSTANCES, eq(USER, user), fields(INCLUDE_EXP_FIELDS, excludeId())))
+                .forEach(exp -> {
+                    final String exploratoryName = exp.getString(EXPLORATORY_NAME);
+                    final String project = exp.getString(PROJECT);
+                    final String endpoint = exp.getString(ENDPOINT);
+                    addResource(hostList, exp, STATUS, ResourceType.EXPLORATORY, exploratoryName, project, endpoint);
+                    addComputationalResources(hostList, clusterList, exp, exploratoryName);
+                });
+        final Map<String, List<EnvResource>> clustersByEndpoint = clusterList.stream()
+                .collect(Collectors.groupingBy(EnvResource::getEndpoint));
+        return hostList.stream()
+                .collect(Collectors.groupingBy(EnvResource::getEndpoint)).entrySet()
+                .stream()
+                .collect(Collectors.toMap(Map.Entry::getKey, e -> new EnvResourceList()
+                        .withHostList(!e.getValue().isEmpty() ? e.getValue() : Collections.emptyList())
+                        .withClusterList(clustersByEndpoint.getOrDefault(e.getKey(), clusterList))));
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<UserInstanceDTO> findRunningResourcesForCheckInactivity() {
+        return stream(find(USER_INSTANCES, or(eq(STATUS, RUNNING.toString()),
+                elemMatch(COMPUTATIONAL_RESOURCES, eq(STATUS, RUNNING.toString())))))
+                .map(d -> convertFromDocument(d, UserInstanceDTO.class))
+                .collect(Collectors.toList());
+    }
+
+    private EnvResource toEnvResource(String name, String instanceId, ResourceType resType, String project,
+                                      String endpoint) {
+        return new EnvResource(instanceId, name, resType, project, endpoint);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void addComputationalResources(List<EnvResource> hostList, List<EnvResource> clusterList, Document exp,
+                                           String exploratoryName) {
+        final String project = exp.getString(PROJECT);
+        getComputationalResources(exp)
+                .forEach(comp -> addComputational(hostList, clusterList, exploratoryName, comp, project,
+                        exp.getString(ENDPOINT)));
+    }
+
+    private List<Document> getComputationalResources(Document userInstanceDocument) {
+        return (List<Document>) userInstanceDocument.getOrDefault(COMPUTATIONAL_RESOURCES, Collections.emptyList());
+    }
+
+    private void addComputational(List<EnvResource> hostList, List<EnvResource> clusterList, String exploratoryName,
+                                  Document computational, String project, String endpoint) {
+        final List<EnvResource> resourceList = DataEngineType.CLOUD_SERVICE ==
+                DataEngineType.fromDockerImageName(computational.getString(IMAGE)) ? clusterList :
+                hostList;
+        addResource(resourceList, computational, STATUS, ResourceType.COMPUTATIONAL,
+                String.join("_", exploratoryName, computational.getString(COMPUTATIONAL_NAME)), project, endpoint);
+    }
+
+    /**
+     * Updates the status of exploratory and computational for user.
+     *
+     * @param user    the name of user.
+     * @param project name of project
+     * @param list    the status of node.
+     */
+    public void updateEnvStatus(String user, String project, EnvResourceList list) {
+        if (list != null && notEmpty(list.getHostList())) {
+            updateEdgeStatus(user, list.getHostList());
+            if (!list.getHostList().isEmpty()) {
+                stream(find(USER_INSTANCES, eq(USER, user),
+                        fields(INCLUDE_EXP_UPDATE_FIELDS, excludeId())))
+                        .filter(this::instanceIdPresent)
+                        .forEach(exp -> updateUserResourceStatuses(user, project, list, exp));
+            }
+        }
+    }
+
+    public Set<String> fetchActiveEnvUsers() {
+        return Stream.concat(
+                stream(find(USER_INSTANCES, eq(STATUS, UserInstanceStatus.RUNNING.toString()),
+                        fields(include(USER), excludeId()))).map(d -> d.getString(USER)),
+                stream(find(USER_EDGE, eq(EDGE_STATUS, UserInstanceStatus.RUNNING.toString()),
+                        fields(include(ID)))).map(d -> d.getString(ID))
+        ).collect(Collectors.toSet());
+    }
+
+    public Set<String> fetchUsersNotIn(Set<String> users) {
+        return stream(find(USER_EDGE, not(in(ID, users)),
+                fields(include(ID)))).map(d -> d.getString(ID))
+                .collect(Collectors.toSet());
+    }
+
+    @SuppressWarnings("unchecked")
+    private void updateUserResourceStatuses(String user, String project, EnvResourceList list, Document exp) {
+        final String exploratoryName = exp.getString(EXPLORATORY_NAME);
+        getEnvResourceAndRemove(list.getHostList(), exp.getString(INSTANCE_ID))
+                .ifPresent(resource -> updateExploratoryStatus(user, project, exploratoryName,
+                        exp.getString(STATUS), resource.getStatus()));
+
+        (getComputationalResources(exp))
+                .stream()
+                .filter(this::instanceIdPresent)
+                .forEach(comp -> updateComputational(user, project, list, exploratoryName, comp));
+    }
+
+    private void updateComputational(String user, String project, EnvResourceList list, String exploratoryName, Document comp) {
+        final List<EnvResource> listToCheck = DataEngineType.CLOUD_SERVICE ==
+                DataEngineType.fromDockerImageName(comp.getString(IMAGE)) ?
+                list.getClusterList() : list.getHostList();
+        getEnvResourceAndRemove(listToCheck, comp.getString(INSTANCE_ID))
+                .ifPresent(resource -> updateComputationalStatus(user, project, exploratoryName,
+                        comp.getString(ComputationalDAO.COMPUTATIONAL_NAME), comp.getString(STATUS), resource.getStatus()));
+    }
+
+    private boolean instanceIdPresent(Document d) {
+        return nonNull(d.getString(INSTANCE_ID));
+    }
+
+    private Optional<String> getInstanceId(Document document) {
+        return Optional.ofNullable(document.getString(INSTANCE_ID));
+    }
+
+
+    /**
+     * Find and return the id of instance for EDGE node.
+     *
+     * @param user the name of user.
+     */
+    private Optional<Document> getEdgeNode(String user) {
+        return findOne(USER_EDGE,
+                eq(ID, user),
+                fields(INCLUDE_EDGE_FIELDS, excludeId()));
+    }
+
+    /**
+     * Find and return the resource item for given id (of instance or cluster) or <b>null<b> otherwise.
+     *
+     * @param list the list of resources.
+     * @param id   the id of instance or cluster.
+     */
+    private Optional<EnvResource> getEnvResourceAndRemove(List<EnvResource> list, String id) {
+        if (list != null) {
+            return IntStream.range(0, list.size())
+                    .filter(i -> list.get(i).getId().equals(id))
+                    .mapToObj(i -> getAndRemove(list, i)).findAny();
+        }
+        return Optional.empty();
+    }
+
+    private EnvResource getAndRemove(List<EnvResource> list, int i) {
+        final EnvResource envResource = list.get(i);
+        list.remove(i);
+        return envResource;
+    }
+
+    /**
+     * Translate the status of instance in Amazon into exploratory's status.
+     *
+     * @param oldStatus the current status of exploratory.
+     * @param newStatus the current status of instance in Amazon.
+     */
+    private UserInstanceStatus getInstanceNewStatus(UserInstanceStatus oldStatus, String newStatus) {
+        /* AWS statuses: pending, running, shutting-down, terminated, stopping, stopped */
+        UserInstanceStatus status;
+        if ("pending".equalsIgnoreCase(newStatus) || "stopping".equalsIgnoreCase(newStatus)) {
+            return oldStatus;
+        } else if ("shutting-down".equalsIgnoreCase(newStatus)) {
+            status = TERMINATING;
+        } else {
+            status = UserInstanceStatus.of(newStatus);
+        }
+
+        switch (oldStatus) {
+            case CREATING_IMAGE:
+                return !status.in(UserInstanceStatus.TERMINATED, TERMINATING,
+                        UserInstanceStatus.RUNNING) ? status : oldStatus;
+            case CREATING:
+                return (status.in(UserInstanceStatus.TERMINATED, UserInstanceStatus.STOPPED) ? status : oldStatus);
+            case RUNNING:
+            case STOPPING:
+                return (status.in(TERMINATING, UserInstanceStatus.TERMINATED,
+                        UserInstanceStatus.STOPPING, UserInstanceStatus.STOPPED) ? status : oldStatus);
+            case STARTING:
+                return (status.in(TERMINATING, UserInstanceStatus.TERMINATED,
+                        UserInstanceStatus.STOPPING) ? status : oldStatus);
+            case STOPPED:
+                return (status.in(TERMINATING, UserInstanceStatus.TERMINATED,
+                        UserInstanceStatus.RUNNING) ? status : oldStatus);
+            case TERMINATING:
+                return (status.in(UserInstanceStatus.TERMINATED) ? status : oldStatus);
+            case FAILED:
+            case TERMINATED:
+            default:
+                return oldStatus;
+        }
+    }
+
+    /**
+     * Updates the status of EDGE node for user.
+     *
+     * @param user     the name of user.
+     * @param hostList list with instance ids for edge resources
+     * @throws DatalabException in case of exception
+     */
+    private void updateEdgeStatus(String user, List<EnvResource> hostList) {
+        LOGGER.trace("Update EDGE status for user {}", user);
+        getEdgeNode(user)
+                .ifPresent(edge -> getInstanceId(edge)
+                        .ifPresent(instanceId -> getEnvResourceAndRemove(hostList, instanceId)
+                                .ifPresent(r -> updateEdgeStatus(user, edge, instanceId, r))));
+
+    }
+
+    private void updateEdgeStatus(String user, Document edge, String instanceId, EnvResource r) {
+        final String oldStatus = edge.getString(EDGE_STATUS);
+        LOGGER.trace("Update EDGE status for user {} with instance_id {} from {} to {}",
+                user, instanceId, oldStatus, r.getStatus());
+        UserInstanceStatus oStatus =
+                (oldStatus == null ? UserInstanceStatus.CREATING : UserInstanceStatus.of(oldStatus));
+        UserInstanceStatus status = oStatus != FAILED ? getInstanceNewStatus(oStatus, r.getStatus()) :
+                UserInstanceStatus.of(r.getStatus());
+        LOGGER.trace("EDGE status translated for user {} with instanceId {} from {} to {}",
+                user, instanceId, r.getStatus(), status);
+        Optional.ofNullable(status)
+                .filter(s -> s != oStatus)
+                .ifPresent(s -> {
+                    LOGGER.debug("EDGE status will be updated from {} to {}", oldStatus, status);
+                    updateOne(USER_EDGE, eq(ID, user),
+                            Updates.set(EDGE_STATUS, status.toString()));
+                });
+    }
+
+    /**
+     * Update the status of exploratory if it needed.
+     *
+     * @param user            the user name
+     * @param project         project name
+     * @param exploratoryName the name of exploratory
+     * @param oldStatus       old status
+     * @param newStatus       new status
+     */
+    private void updateExploratoryStatus(String user, String project, String exploratoryName,
+                                         String oldStatus, String newStatus) {
+        LOGGER.trace("Update exploratory status for user {} with exploratory {} from {} to {}", user, exploratoryName,
+                oldStatus, newStatus);
+        UserInstanceStatus oStatus = UserInstanceStatus.of(oldStatus);
+        UserInstanceStatus status = getInstanceNewStatus(oStatus, newStatus);
+        LOGGER.trace("Exploratory status translated for user {} with exploratory {} from {} to {}", user,
+                exploratoryName, newStatus, status);
+
+        if (oStatus != status) {
+            LOGGER.debug("Exploratory status for user {} with exploratory {} will be updated from {} to {}", user,
+                    exploratoryName, oldStatus, status);
+            updateOne(USER_INSTANCES,
+                    exploratoryCondition(user, exploratoryName, project),
+                    Updates.set(STATUS, status.toString()));
+        }
+    }
+
+    /**
+     * Translate the status of cluster in Amazon into computational's status.
+     *
+     * @param oldStatus the current status of computational.
+     * @param newStatus the current status of cluster in Amazon.
+     */
+    private UserInstanceStatus getComputationalNewStatus(UserInstanceStatus oldStatus, String newStatus) {
+        /* AWS statuses: bootstrapping, running, starting, terminated, terminated_with_errors, terminating, waiting */
+        UserInstanceStatus status;
+        if ("terminated".equalsIgnoreCase(newStatus) || "terminated_with_errors".equalsIgnoreCase(newStatus)) {
+            status = UserInstanceStatus.TERMINATED;
+        } else {
+            status = Optional.ofNullable(UserInstanceStatus.of(newStatus)).orElse(oldStatus);
+        }
+
+        switch (oldStatus) {
+            case CREATING:
+            case CONFIGURING:
+            case RUNNING:
+                return (status.in(UserInstanceStatus.TERMINATED, TERMINATING,
+                        UserInstanceStatus.STOPPING, UserInstanceStatus.STOPPED) ? status : oldStatus);
+            case TERMINATING:
+                return (status.in(UserInstanceStatus.TERMINATED) ? status : oldStatus);
+            case STARTING:
+            case STOPPED:
+            case STOPPING:
+                return status;
+            case FAILED:
+            case TERMINATED:
+            default:
+                return oldStatus;
+        }
+    }
+
+    /**
+     * Update the status of exploratory if it needed.
+     *
+     * @param user              the user name.
+     * @param project           project name
+     * @param exploratoryName   the name of exploratory.
+     * @param computationalName the name of computational.
+     * @param oldStatus         old status.
+     * @param newStatus         new status.
+     */
+    private void updateComputationalStatus(String user, String project, String exploratoryName, String computationalName,
+                                           String oldStatus, String newStatus) {
+        LOGGER.trace("Update computational status for user {} with exploratory {} and computational {} from {} to {}",
+                user, exploratoryName, computationalName, oldStatus, newStatus);
+        UserInstanceStatus oStatus = UserInstanceStatus.of(oldStatus);
+        UserInstanceStatus status = getComputationalNewStatus(oStatus, newStatus);
+        LOGGER.trace("Translate computational status for user {} with exploratory {} and computational {} from {} to" +
+                        " " +
+                        "{}",
+                user, exploratoryName, computationalName, newStatus, status);
+
+        if (oStatus != status) {
+            LOGGER.debug("Computational status for user {} with exploratory {} and computational {} will be updated " +
+                            "from {} to {}",
+                    user, exploratoryName, computationalName, oldStatus, status);
+            if (status == UserInstanceStatus.TERMINATED &&
+                    terminateComputationalSpot(user, project, exploratoryName, computationalName)) {
+                return;
+            }
+            Document values = new Document(COMPUTATIONAL_STATUS_FILTER, status.toString());
+            updateOne(USER_INSTANCES,
+                    and(exploratoryCondition(user, exploratoryName, project),
+                            elemMatch(COMPUTATIONAL_RESOURCES,
+                                    and(eq(ComputationalDAO.COMPUTATIONAL_NAME, computationalName))
+                            )
+                    ),
+                    new Document(SET, values));
+        }
+    }
+
+    /**
+     * Terminate EMR if it is spot.
+     *
+     * @param user              the user name.
+     * @param project           name of project
+     * @param exploratoryName   the name of exploratory.
+     * @param computationalName the name of computational.
+     * @return <b>true</b> if computational is spot and should be terminated by docker, otherwise <b>false</b>.
+     */
+    private boolean terminateComputationalSpot(String user, String project, String exploratoryName, String computationalName) {
+        LOGGER.trace("Check computatation is spot for user {} with exploratory {} and computational {}", user,
+                exploratoryName, computationalName);
+        Document doc = findOne(USER_INSTANCES,
+                exploratoryCondition(user, exploratoryName, project),
+                and(elemMatch(COMPUTATIONAL_RESOURCES,
+                        and(eq(ComputationalDAO.COMPUTATIONAL_NAME, computationalName),
+                                eq(COMPUTATIONAL_SPOT, true),
+                                not(eq(STATUS, TERMINATED.toString())))),
+                        include(COMPUTATIONAL_RESOURCES + "." + COMPUTATIONAL_SPOT))
+        ).orElse(null);
+        if (doc == null || doc.get(COMPUTATIONAL_RESOURCES) == null) {
+            return false;
+        }
+
+        UserInfo userInfo = null;
+        if (userInfo == null) {
+            // User logged off. Computational will be terminated when user logged in.
+            return true;
+        }
+
+        String accessToken = userInfo.getAccessToken();
+        LOGGER.debug("Computational will be terminated for user {} with exploratory {} and computational {}",
+                user, exploratoryName, computationalName);
+        try {
+            // Send post request to provisioning service to terminate spot EMR.
+            ComputationalResourceAws computational = new ComputationalResourceAws();
+            SelfServiceApplication.getInjector().injectMembers(computational);
+            UserInfo ui = new UserInfo(user, accessToken);
+            computational.terminate(ui, project, exploratoryName, computationalName);
+        } catch (Exception e) {
+            // Cannot terminate EMR, just update status to terminated
+            LOGGER.warn("Can't terminate computational for user {} with exploratory {} and computational {}. {}",
+                    user, exploratoryName, computationalName, e.getLocalizedMessage(), e);
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Add the resource to list if it have instance_id.
+     *
+     * @param list            the list to add.
+     * @param document        document with resource.
+     * @param statusFieldName name of field that contains status information
+     * @param resourceType    type if resource EDGE/NOTEBOOK
+     */
+    private void addResource(List<EnvResource> list, Document document, String statusFieldName,
+                             ResourceType resourceType, String name, String project, String endpoint) {
+        LOGGER.trace("Add resource from {}", document);
+        getInstanceId(document).ifPresent(instanceId ->
+                Optional.ofNullable(UserInstanceStatus.of(document.getString(statusFieldName)))
+                        .filter(s -> s.in(CONFIGURING, CREATING, RUNNING, STARTING, STOPPED, STOPPING, TERMINATING) ||
+                                (FAILED == s && ResourceType.EDGE == resourceType))
+                        .ifPresent(s -> list.add(toEnvResource(name, instanceId, resourceType, project, endpoint))));
+    }
+
+    private boolean notEmpty(List<EnvResource> hostList) {
+        return hostList != null && !hostList.isEmpty();
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ExploratoryDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ExploratoryDAO.java
new file mode 100644
index 0000000..599acaa
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ExploratoryDAO.java
@@ -0,0 +1,479 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+
+import com.epam.datalab.backendapi.util.DateRemoverUtil;
+import com.epam.datalab.dto.ResourceURL;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.dto.StatusEnvBaseDTO;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.exploratory.ExploratoryStatusDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.google.inject.Singleton;
+import com.mongodb.client.result.UpdateResult;
+import lombok.extern.slf4j.Slf4j;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.backendapi.dao.MongoCollections.USER_INSTANCES;
+import static com.epam.datalab.backendapi.dao.SchedulerJobDAO.SCHEDULER_DATA;
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.in;
+import static com.mongodb.client.model.Filters.not;
+import static com.mongodb.client.model.Filters.or;
+import static com.mongodb.client.model.Projections.exclude;
+import static com.mongodb.client.model.Projections.excludeId;
+import static com.mongodb.client.model.Projections.fields;
+import static com.mongodb.client.model.Projections.include;
+import static com.mongodb.client.model.Updates.set;
+import static java.util.stream.Collectors.toList;
+
+/**
+ * DAO for user exploratory.
+ */
+@Slf4j
+@Singleton
+public class ExploratoryDAO extends BaseDAO {
+    public static final String COMPUTATIONAL_RESOURCES = "computational_resources";
+    static final String EXPLORATORY_ID = "exploratory_id";
+    static final String EXPLORATORY_NAME = "exploratory_name";
+    static final String UPTIME = "up_time";
+
+    private static final String COMPUTATIONAL_NAME = "computational_name";
+    private static final String EXPLORATORY_URL = "exploratory_url";
+    private static final String EXPLORATORY_URL_DESC = "description";
+    private static final String EXPLORATORY_URL_URL = "url";
+    private static final String EXPLORATORY_USER = "exploratory_user";
+    private static final String EXPLORATORY_PASS = "exploratory_pass";
+    private static final String CLUSTER_CONFIG = "cluster_config";
+    private static final String EXPLORATORY_PRIVATE_IP = "private_ip";
+    public static final String EXPLORATORY_NOT_FOUND_MSG = "Exploratory for user %s with name %s not found";
+    private static final String EXPLORATORY_LAST_ACTIVITY = "last_activity";
+    private static final String PROJECT = "project";
+    private static final String ENDPOINT = "endpoint";
+
+    public ExploratoryDAO() {
+        log.info("{} is initialized", getClass().getSimpleName());
+    }
+
+    static Bson exploratoryCondition(String user, String exploratoryName, String project) {
+        return and(eq(USER, user), eq(EXPLORATORY_NAME, exploratoryName), eq(PROJECT, project));
+    }
+
+    private static Bson runningExploratoryCondition(String user, String exploratoryName, String project) {
+        return and(eq(USER, user), eq(PROJECT, project),
+                and(eq(EXPLORATORY_NAME, exploratoryName), eq(STATUS, UserInstanceStatus.RUNNING.toString())));
+    }
+
+    static Bson runningExploratoryAndComputationalCondition(String user, String project, String exploratoryName,
+                                                            String computationalName) {
+        return and(eq(USER, user), eq(PROJECT, project),
+                and(eq(EXPLORATORY_NAME, exploratoryName), eq(STATUS, UserInstanceStatus.RUNNING.toString()),
+                        eq(COMPUTATIONAL_RESOURCES + "." + COMPUTATIONAL_NAME, computationalName),
+                        eq(COMPUTATIONAL_RESOURCES + "." + STATUS, UserInstanceStatus.RUNNING.toString())));
+    }
+
+    public List<UserInstanceDTO> findExploratories(String user, String project) {
+        return getUserInstances(and(eq(USER, user), eq(PROJECT, project)), true);
+    }
+
+    /**
+     * Finds and returns the info of all user's running notebooks.
+     *
+     * @param user user name.
+     */
+    public List<UserInstanceDTO> fetchRunningExploratoryFields(String user) {
+        return getUserInstances(and(eq(USER, user), eq(STATUS, UserInstanceStatus.RUNNING.toString())), false);
+    }
+
+    public List<UserInstanceDTO> fetchRunningExploratoryFieldsForProject(String project) {
+        return getUserInstances(and(eq(PROJECT, project), eq(STATUS, UserInstanceStatus.RUNNING.toString())), false);
+    }
+
+    public List<UserInstanceDTO> fetchRunningExploratoryFieldsForProject(String project, List<String> endpoints) {
+        return getUserInstances(and(eq(PROJECT, project), eq(STATUS, UserInstanceStatus.RUNNING.toString()), in(ENDPOINT, endpoints)), false);
+    }
+
+    public List<UserInstanceDTO> fetchExploratoryFieldsForProject(String project) {
+        return getUserInstances(and(eq(PROJECT, project)), false);
+    }
+
+    public List<UserInstanceDTO> fetchExploratoryFieldsForProjectWithComp(String project) {
+        return getUserInstances(and(eq(PROJECT, project)), true);
+    }
+
+    public List<UserInstanceDTO> fetchExploratoryFieldsForProjectWithComp(List<String> projects) {
+        return getUserInstances(and(in(PROJECT, projects)), true);
+    }
+
+    public List<UserInstanceDTO> findExploratories(String project, String endpoint, String user) {
+        return getUserInstances(and(eq(PROJECT, project), eq(ENDPOINT, endpoint), eq(USER, user)), true);
+    }
+
+    public List<UserInstanceDTO> fetchUserExploratoriesWhereStatusIn(String user, boolean computationalFieldsRequired,
+                                                                     UserInstanceStatus... statuses) {
+        final List<String> statusList = statusList(statuses);
+        return getUserInstances(
+                and(
+                        eq(USER, user),
+                        in(STATUS, statusList)
+                ),
+                computationalFieldsRequired);
+    }
+
+    /**
+     * Finds and returns the info of all user's notebooks whose status or status of affiliated computational resource
+     * is present among predefined ones.
+     *
+     * @param user                  user name.
+     * @param exploratoryStatuses   array of exploratory statuses.
+     * @param computationalStatuses array of computational statuses.
+     */
+    public List<UserInstanceDTO> fetchUserExploratoriesWhereStatusIn(String user,
+                                                                     List<UserInstanceStatus> exploratoryStatuses,
+                                                                     UserInstanceStatus... computationalStatuses) {
+        final List<String> exploratoryStatusList = statusList(exploratoryStatuses);
+        final List<String> computationalStatusList = statusList(computationalStatuses);
+        return getUserInstances(
+                and(
+                        eq(USER, user),
+                        or(in(STATUS, exploratoryStatusList),
+                                in(COMPUTATIONAL_RESOURCES + "." + STATUS, computationalStatusList))
+                ),
+                false);
+    }
+
+    public List<UserInstanceDTO> fetchProjectExploratoriesWhereStatusIn(String project,
+                                                                        List<UserInstanceStatus> exploratoryStatuses,
+                                                                        UserInstanceStatus... computationalStatuses) {
+        final List<String> exploratoryStatusList = statusList(exploratoryStatuses);
+        final List<String> computationalStatusList = statusList(computationalStatuses);
+        return getUserInstances(
+                and(
+                        eq(PROJECT, project),
+                        or(in(STATUS, exploratoryStatusList),
+                                in(COMPUTATIONAL_RESOURCES + "." + STATUS, computationalStatusList))
+                ),
+                false);
+    }
+
+    public List<UserInstanceDTO> fetchProjectEndpointExploratoriesWhereStatusIn(String project, List<String> endpoints,
+                                                                                List<UserInstanceStatus> exploratoryStatuses,
+                                                                                UserInstanceStatus... computationalStatuses) {
+        final List<String> exploratoryStatusList = statusList(exploratoryStatuses);
+        final List<String> computationalStatusList = statusList(computationalStatuses);
+        return getUserInstances(
+                and(
+                        eq(PROJECT, project),
+                        in(ENDPOINT, endpoints),
+                        or(in(STATUS, exploratoryStatusList),
+                                in(COMPUTATIONAL_RESOURCES + "." + STATUS, computationalStatusList))
+                ),
+                false);
+    }
+
+    public List<UserInstanceDTO> fetchProjectExploratoriesWhereStatusNotIn(String project, String endpoint,
+                                                                           UserInstanceStatus... statuses) {
+        final List<String> statusList = statusList(statuses);
+        return getUserInstances(
+                and(
+                        eq(PROJECT, project),
+                        eq(ENDPOINT, endpoint),
+                        not(in(STATUS, statusList))
+                ),
+                false);
+    }
+
+    public List<UserInstanceDTO> fetchExploratoriesByEndpointWhereStatusNotIn(String endpoint,
+                                                                              List<UserInstanceStatus> statuses) {
+        final List<String> exploratoryStatusList = statusList(statuses);
+
+        return getUserInstances(
+                and(
+                        eq(ENDPOINT, endpoint),
+                        not(in(STATUS, exploratoryStatusList))
+                ),
+                false);
+    }
+
+    private List<UserInstanceDTO> getUserInstances(Bson condition, boolean computationalFieldsRequired) {
+        return stream(getCollection(USER_INSTANCES)
+                .find(condition)
+                .projection(computationalFieldsRequired ? null : fields(exclude(COMPUTATIONAL_RESOURCES))))
+                .map(d -> convertFromDocument(d, UserInstanceDTO.class))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Finds and returns the info about all exploratories in database.
+     **/
+    public List<UserInstanceDTO> getInstances() {
+        return stream(getCollection(USER_INSTANCES)
+                .find())
+                .map(d -> convertFromDocument(d, UserInstanceDTO.class))
+                .collect(Collectors.toList());
+    }
+
+    public void updateLastActivity(String user, String exploratoryName, LocalDateTime lastActivity) {
+        updateOne(USER_INSTANCES, and(eq(USER, user), eq(EXPLORATORY_NAME, exploratoryName)),
+                set(EXPLORATORY_LAST_ACTIVITY, toDate(lastActivity)));
+    }
+
+    private Date toDate(LocalDateTime lastActivity) {
+        return Date.from(lastActivity.atZone(ZoneId.systemDefault()).toInstant());
+    }
+
+    /**
+     * Finds and returns the info of exploratory (without info about computational resources).
+     *
+     * @param user            user name.
+     * @param project         project name
+     * @param exploratoryName the name of exploratory.
+     */
+    public UserInstanceDTO fetchExploratoryFields(String user, String project, String exploratoryName) {
+        return getExploratory(user, project, exploratoryName, false).orElseThrow(() ->
+                new ResourceNotFoundException(String.format(EXPLORATORY_NOT_FOUND_MSG, user, exploratoryName)));
+
+    }
+
+    public UserInstanceDTO fetchExploratoryFields(String user, String project, String exploratoryName, boolean includeCompResources) {
+        return getExploratory(user, project, exploratoryName, includeCompResources).orElseThrow(() ->
+                new ResourceNotFoundException(String.format(EXPLORATORY_NOT_FOUND_MSG, user, exploratoryName)));
+
+    }
+
+    private Optional<UserInstanceDTO> getExploratory(String user, String project, String exploratoryName,
+                                                     boolean includeCompResources) {
+        return findOne(USER_INSTANCES,
+                exploratoryCondition(user, exploratoryName, project),
+                includeCompResources ? null : fields(exclude(COMPUTATIONAL_RESOURCES)),
+                UserInstanceDTO.class);
+    }
+
+    /**
+     * Finds and returns the info of running exploratory with running cluster.
+     *
+     * @param user              user name.
+     * @param project           name of project
+     * @param exploratoryName   name of exploratory.
+     * @param computationalName name of cluster
+     */
+    public UserInstanceDTO fetchExploratoryFields(String user, String project, String exploratoryName, String computationalName) {
+        return findOne(USER_INSTANCES,
+                runningExploratoryAndComputationalCondition(user, project, exploratoryName, computationalName),
+                UserInstanceDTO.class)
+                .orElseThrow(() -> new DatalabException(String.format("Running notebook %s with running cluster %s not " +
+                                "found for user %s",
+                        exploratoryName, computationalName, user)));
+    }
+
+    /**
+     * Finds and returns the info of running exploratory.
+     *
+     * @param user            user name.
+     * @param project         project
+     * @param exploratoryName name of exploratory.
+     */
+    public UserInstanceDTO fetchRunningExploratoryFields(String user, String project, String exploratoryName) {
+        return findOne(USER_INSTANCES, runningExploratoryCondition(user, exploratoryName, project),
+                fields(exclude(COMPUTATIONAL_RESOURCES)), UserInstanceDTO.class)
+                .orElseThrow(() -> new DatalabException(
+                        String.format("Running exploratory instance for user %s with name %s not found.",
+                                user, exploratoryName)));
+    }
+
+    /**
+     * Inserts the info about notebook into Mongo database.
+     *
+     * @param dto the info about notebook
+     */
+    public void insertExploratory(UserInstanceDTO dto) {
+        insertOne(USER_INSTANCES, dto);
+    }
+
+    /**
+     * Updates the status of exploratory in Mongo database.
+     *
+     * @param dto object of exploratory status info.
+     * @return The result of an update operation.
+     */
+    public UpdateResult updateExploratoryStatus(StatusEnvBaseDTO<?> dto) {
+        return updateOne(USER_INSTANCES,
+                exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
+                set(STATUS, dto.getStatus()));
+    }
+
+    /**
+     * Updates status for single exploratory in Mongo database.
+     *
+     * @param user            user.
+     * @param project         project name
+     * @param exploratoryName name of exploratory.
+     * @param newStatus       new status of exploratory.
+     * @return The result of an update operation.
+     */
+    public UpdateResult updateStatusForExploratory(String user, String project, String exploratoryName, UserInstanceStatus newStatus) {
+        return updateOne(USER_INSTANCES,
+                exploratoryCondition(user, exploratoryName, project),
+                set(STATUS, newStatus.toString()));
+    }
+
+    /**
+     * Updates the scheduler's data for exploratory in Mongo database.
+     *
+     * @param user            user.
+     * @param project         name of project
+     * @param exploratoryName name of exploratory.
+     * @param dto             object of scheduler data.
+     * @return The result of an update operation.
+     */
+    public UpdateResult updateSchedulerDataForUserAndExploratory(String user, String project, String exploratoryName,
+                                                                 SchedulerJobDTO dto) {
+        return updateOne(USER_INSTANCES,
+                exploratoryCondition(user, exploratoryName, project),
+                set(SCHEDULER_DATA, Objects.isNull(dto) ? null : convertToBson(dto)));
+    }
+
+    /**
+     * Updates the requirement for reuploading key for single exploratory in Mongo database.
+     *
+     * @param user                user name.
+     * @param project             project name
+     * @param exploratoryName     exploratory's name
+     * @param reuploadKeyRequired true/false.
+     */
+    public void updateReuploadKeyForExploratory(String user, String project, String exploratoryName, boolean reuploadKeyRequired) {
+        updateOne(USER_INSTANCES,
+                exploratoryCondition(user, exploratoryName, project),
+                set(REUPLOAD_KEY_REQUIRED, reuploadKeyRequired));
+    }
+
+
+    /**
+     * Updates the info of exploratory in Mongo database.
+     *
+     * @param dto object of exploratory status info.
+     * @return The result of an update operation.
+     */
+    @SuppressWarnings("serial")
+    public UpdateResult updateExploratoryFields(ExploratoryStatusDTO dto) {
+        Document values = new Document(STATUS, dto.getStatus()).append(UPTIME, dto.getUptime());
+        if (dto.getInstanceId() != null) {
+            values.append(INSTANCE_ID, dto.getInstanceId());
+        }
+        if (dto.getErrorMessage() != null) {
+            values.append(ERROR_MESSAGE, DateRemoverUtil.removeDateFormErrorMessage(dto.getErrorMessage()));
+        }
+        if (dto.getExploratoryId() != null) {
+            values.append(EXPLORATORY_ID, dto.getExploratoryId());
+        }
+
+        if (dto.getLastActivity() != null) {
+            values.append(EXPLORATORY_LAST_ACTIVITY, dto.getLastActivity());
+        }
+
+        if (dto.getResourceUrl() != null) {
+            values.append(EXPLORATORY_URL, dto.getResourceUrl().stream()
+                    .map(url -> {
+                                LinkedHashMap<String, String> map = new LinkedHashMap<>();
+                                map.put(EXPLORATORY_URL_DESC, url.getDescription());
+                                map.put(EXPLORATORY_URL_URL, url.getUrl());
+                                return map;
+                            }
+                    ).collect(Collectors.toList()));
+        } else if (dto.getPrivateIp() != null) {
+            UserInstanceDTO inst = fetchExploratoryFields(dto.getUser(), dto.getProject(), dto.getExploratoryName());
+            if (!inst.getPrivateIp().equals(dto.getPrivateIp()) && inst.getResourceUrl() != null) {
+                values.append(EXPLORATORY_URL, inst.getResourceUrl().stream()
+                        .map(url -> replaceIp(dto.getPrivateIp(), inst, url))
+                        .collect(Collectors.toList()));
+            }
+        }
+
+        if (dto.getPrivateIp() != null) {
+            values.append(EXPLORATORY_PRIVATE_IP, dto.getPrivateIp());
+        }
+        if (dto.getExploratoryUser() != null) {
+            values.append(EXPLORATORY_USER, dto.getExploratoryUser());
+        }
+        if (dto.getExploratoryPassword() != null) {
+            values.append(EXPLORATORY_PASS, dto.getExploratoryPassword());
+        }
+        if (dto.getConfig() != null) {
+            values.append(CLUSTER_CONFIG, dto.getConfig().stream().map(this::convertToBson).collect(toList()));
+        }
+        return updateOne(USER_INSTANCES,
+                exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
+                new Document(SET, values));
+    }
+
+    public void updateExploratoryIp(String user, String project, String ip, String exploratoryName) {
+
+        UserInstanceDTO inst = fetchExploratoryFields(user, project, exploratoryName);
+        if (!inst.getPrivateIp().equals(ip)) {
+            Document values = new Document();
+            values.append(EXPLORATORY_PRIVATE_IP, ip);
+            if (inst.getResourceUrl() != null) {
+                values.append(EXPLORATORY_URL, inst.getResourceUrl().stream()
+                        .map(url -> replaceIp(ip, inst, url)
+                        ).collect(Collectors.toList()));
+            }
+
+            updateOne(USER_INSTANCES,
+                    exploratoryCondition(user, exploratoryName, project),
+                    new Document(SET, values));
+        }
+
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<ClusterConfig> getClusterConfig(String user, String project, String exploratoryName) {
+        return findOne(USER_INSTANCES, and(exploratoryCondition(user, exploratoryName, project), notNull(CLUSTER_CONFIG)),
+                fields(include(CLUSTER_CONFIG), excludeId()))
+                .map(d -> convertFromDocument((List<Document>) d.get(CLUSTER_CONFIG),
+                        new TypeReference<List<ClusterConfig>>() {
+                        }))
+                .orElse(Collections.emptyList());
+    }
+
+    private Map<String, String> replaceIp(String ip, UserInstanceDTO inst, ResourceURL url) {
+        Map<String, String> map = new LinkedHashMap<>();
+        map.put(EXPLORATORY_URL_DESC, url.getDescription());
+        map.put(EXPLORATORY_URL_URL, url.getUrl().replace(inst.getPrivateIp(), ip));
+        return map;
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ExploratoryLibDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ExploratoryLibDAO.java
new file mode 100644
index 0000000..8550fff
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ExploratoryLibDAO.java
@@ -0,0 +1,402 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.util.DateRemoverUtil;
+import com.epam.datalab.dto.exploratory.LibInstallDTO;
+import com.epam.datalab.dto.exploratory.LibInstallStatusDTO;
+import com.epam.datalab.dto.exploratory.LibStatus;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.model.ResourceType;
+import com.epam.datalab.model.library.Library;
+import com.mongodb.client.model.Projections;
+import org.apache.commons.lang3.StringUtils;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.COMPUTATIONAL_RESOURCES;
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.exploratoryCondition;
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.runningExploratoryAndComputationalCondition;
+import static com.epam.datalab.backendapi.dao.MongoCollections.USER_INSTANCES;
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Projections.elemMatch;
+import static com.mongodb.client.model.Projections.excludeId;
+import static com.mongodb.client.model.Projections.fields;
+import static com.mongodb.client.model.Projections.include;
+import static com.mongodb.client.model.Updates.push;
+
+/**
+ * DAO for user libraries.
+ */
+public class ExploratoryLibDAO extends BaseDAO {
+    public static final String EXPLORATORY_LIBS = "libs";
+    public static final String COMPUTATIONAL_LIBS = "computational_libs";
+    public static final String LIB_GROUP = "group";
+    public static final String LIB_NAME = "name";
+    public static final String LIB_VERSION = "version";
+    public static final String LIB_AVAILABLE_VERSION = "available_versions";
+    public static final String LIB_ADDED_PACKAGES = "add_pkgs";
+    private static final String LIB_INSTALL_DATE = "install_date";
+    private static final String LIB_ERROR_MESSAGE = "error_message";
+    private static final String COMPUTATIONAL_NAME_FIELD = "computational_name";
+
+    /**
+     * Return condition for search library into exploratory data.
+     *
+     * @param libraryGroup the name of group.
+     * @param libraryName  the name of library.
+     */
+    private static Bson libraryConditionExploratory(String libraryGroup, String libraryName) {
+        return elemMatch(EXPLORATORY_LIBS,
+                libCondition(libraryGroup, libraryName));
+    }
+
+
+    /**
+     * Return condition for search library into computational data.
+     *
+     * @param computationalName computational name
+     * @param libraryGroup      the name of group.
+     * @param libraryName       the name of library.
+     */
+    private static Bson libraryConditionComputational(String computationalName, String libraryGroup,
+                                                      String libraryName) {
+        return elemMatch(COMPUTATIONAL_LIBS + "." + computationalName,
+                and(eq(LIB_GROUP, libraryGroup), eq(LIB_NAME, libraryName)));
+    }
+
+    /**
+     * Return field filter for libraries properties in exploratory data.
+     *
+     * @param fieldName
+     * @return
+     */
+    private static String libraryFieldFilter(String fieldName) {
+        return EXPLORATORY_LIBS + FIELD_SET_DELIMETER + fieldName;
+    }
+
+
+    private static String computationalLibraryFieldFilter(String computational, String fieldName) {
+        return COMPUTATIONAL_LIBS + "." + computational + FIELD_SET_DELIMETER + fieldName;
+    }
+
+    private Document findLibraries(String user, String project, String exploratoryName, Bson include) {
+        Optional<Document> opt = findOne(USER_INSTANCES,
+                exploratoryCondition(user, exploratoryName, project),
+                fields(excludeId(), include));
+
+        return opt.orElseGet(Document::new);
+
+    }
+
+    public List<Library> getLibraries(String user, String project, String exploratoryName) {
+        final Document libsDocument = findAllLibraries(user, project, exploratoryName);
+        return Stream
+                .concat(
+                        libraryStream(libsDocument, exploratoryName, EXPLORATORY_LIBS, ResourceType.EXPLORATORY),
+                        computationalLibStream(libsDocument))
+                .collect(Collectors.toList());
+    }
+
+    public Document findAllLibraries(String user, String project, String exploratoryName) {
+        return findLibraries(user, project, exploratoryName, include(EXPLORATORY_LIBS, COMPUTATIONAL_LIBS,
+                COMPUTATIONAL_RESOURCES));
+    }
+
+    public Document findExploratoryLibraries(String user, String project, String exploratoryName) {
+        return findLibraries(user, project, exploratoryName, include(EXPLORATORY_LIBS));
+    }
+
+    public Document findComputationalLibraries(String user, String project, String exploratoryName, String computationalName) {
+        return findLibraries(user, project, exploratoryName, include(COMPUTATIONAL_LIBS + "." + computationalName));
+    }
+
+    @SuppressWarnings("unchecked")
+    public Library getLibrary(String user, String project, String exploratoryName, String libraryGroup, String libraryName) {
+        Optional<Document> userInstance = findOne(USER_INSTANCES,
+                and(exploratoryCondition(user, exploratoryName, project),
+                        elemMatch(EXPLORATORY_LIBS,
+                                and(eq(LIB_GROUP, libraryGroup), eq(LIB_NAME, libraryName))
+                        )),
+                Projections.fields(excludeId(), Projections.include(EXPLORATORY_LIBS)));
+
+        if (userInstance.isPresent()) {
+            final Object exloratoryLibs = userInstance.get().get(EXPLORATORY_LIBS);
+            List<Document> libs = exloratoryLibs != null ? (List<Document>) exloratoryLibs : Collections.emptyList();
+            return libs.stream()
+                    .filter(libraryPredicate(libraryGroup, libraryName))
+                    .map(d -> convertFromDocument(d, Library.class))
+                    .findAny().orElse(null);
+
+        }
+
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Library getLibrary(String user, String project, String exploratoryName, String computationalName,
+                              String libraryGroup, String libraryName) {
+        Optional<Document> libraryStatus = findOne(USER_INSTANCES,
+                and(runningExploratoryAndComputationalCondition(user, project, exploratoryName, computationalName),
+                        libraryConditionComputational(computationalName, libraryGroup, libraryName)
+                ),
+
+                Projections.fields(excludeId(),
+                        Projections.include(
+                                COMPUTATIONAL_LIBS + "." + computationalName + "." + STATUS,
+                                COMPUTATIONAL_LIBS + "." + computationalName + "." + LIB_GROUP,
+                                COMPUTATIONAL_LIBS + "." + computationalName + "." + LIB_NAME)
+                )
+        );
+
+        return libraryStatus.map(document -> ((List<Document>) (((Document) document.get(COMPUTATIONAL_LIBS)).get(computationalName)))
+                .stream()
+                .filter(libraryPredicate(libraryGroup, libraryName))
+                .map(l -> convertFromDocument(l, Library.class))
+                .findAny().orElse(null)).orElse(null);
+    }
+
+    private Predicate<Document> libraryPredicate(String libraryGroup, String libraryName) {
+        return l -> libraryGroup.equals(l.getString(LIB_GROUP))
+                && libraryName.equals(l.getString(LIB_NAME));
+    }
+
+    /**
+     * Add the user's library for exploratory into database.
+     *
+     * @param user            user name.
+     * @param project         project name
+     * @param exploratoryName name of exploratory.
+     * @param library         library.
+     * @return <b>true</b> if operation was successful, otherwise <b>false</b>.
+     */
+    public boolean addLibrary(String user, String project, String exploratoryName, LibInstallDTO library, boolean reinstall) {
+        Optional<Document> opt = findOne(USER_INSTANCES,
+                and(exploratoryCondition(user, exploratoryName, project),
+                        elemMatch(EXPLORATORY_LIBS,
+                                and(eq(LIB_GROUP, library.getGroup()), eq(LIB_NAME, library.getName())))));
+        if (!opt.isPresent()) {
+            updateOne(USER_INSTANCES,
+                    exploratoryCondition(user, exploratoryName, project),
+                    push(EXPLORATORY_LIBS, convertToBson(library)));
+            return true;
+        } else {
+            Document values = addLibraryFields(library);
+            if (reinstall) {
+                values.append(libraryFieldFilter(LIB_INSTALL_DATE), null);
+                values.append(libraryFieldFilter(LIB_ERROR_MESSAGE), null);
+            }
+
+            updateOne(USER_INSTANCES, and(exploratoryCondition(user, exploratoryName, project),
+                    elemMatch(EXPLORATORY_LIBS,
+                            and(eq(LIB_GROUP, library.getGroup()), eq(LIB_NAME, library.getName())))),
+                    new Document(SET, values));
+            return false;
+        }
+    }
+
+    /**
+     * Add the user's library for exploratory into database.
+     *
+     * @param user              user name.
+     * @param project           project name
+     * @param exploratoryName   name of exploratory.
+     * @param computationalName name of computational.
+     * @param library           library.
+     * @return <b>true</b> if operation was successful, otherwise <b>false</b>.
+     */
+    public boolean addLibrary(String user, String project, String exploratoryName, String computationalName,
+                              LibInstallDTO library, boolean reinstall) {
+
+        Optional<Document> opt = findOne(USER_INSTANCES,
+                and(runningExploratoryAndComputationalCondition(user, project, exploratoryName, computationalName),
+                        eq(COMPUTATIONAL_LIBS + "." + computationalName + "." + LIB_GROUP, library.getGroup()),
+                        eq(COMPUTATIONAL_LIBS + "." + computationalName + "." + LIB_NAME, library.getName())));
+
+        if (!opt.isPresent()) {
+            updateOne(USER_INSTANCES,
+                    runningExploratoryAndComputationalCondition(user, project, exploratoryName, computationalName),
+                    push(COMPUTATIONAL_LIBS + "." + computationalName, convertToBson(library)));
+            return true;
+        } else {
+            Document values = addComputationalLibraryFields(computationalName, library);
+            if (reinstall) {
+                values.append(computationalLibraryFieldFilter(computationalName, LIB_INSTALL_DATE), null);
+                values.append(computationalLibraryFieldFilter(computationalName, LIB_ERROR_MESSAGE), null);
+            }
+
+            updateOne(USER_INSTANCES, and(
+                    exploratoryCondition(user, exploratoryName, project),
+                    eq(COMPUTATIONAL_LIBS + "." + computationalName + "." + LIB_GROUP, library.getGroup()),
+                    eq(COMPUTATIONAL_LIBS + "." + computationalName + "." + LIB_NAME, library.getName())),
+
+                    new Document(SET, values));
+
+            return false;
+        }
+    }
+
+    /**
+     * Updates the info about libraries for exploratory/computational in Mongo database.
+     *
+     * @param dto object of computational resource status.
+     */
+    public void updateLibraryFields(LibInstallStatusDTO dto) {
+        if (dto.getLibs() == null) {
+            return;
+        }
+
+        if (StringUtils.isEmpty(dto.getComputationalName())) {
+            updateExploratoryLibraryFields(dto);
+        } else {
+            updateComputationalLibraryFields(dto);
+        }
+    }
+
+    private void updateExploratoryLibraryFields(LibInstallStatusDTO dto) {
+        for (LibInstallDTO lib : dto.getLibs()) {
+            try {
+                Document values = updateLibraryFields(lib, dto.getUptime());
+
+                updateOne(USER_INSTANCES,
+                        and(exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
+                                libraryConditionExploratory(lib.getGroup(), lib.getName())),
+                        new Document(SET, values));
+            } catch (Exception e) {
+                throw new DatalabException(String.format("Could not update library %s for %s",
+                        lib, dto.getExploratoryName()), e);
+            }
+        }
+    }
+
+    private void updateComputationalLibraryFields(LibInstallStatusDTO dto) {
+        for (LibInstallDTO lib : dto.getLibs()) {
+            try {
+                Document values = updateComputationalLibraryFields(dto.getComputationalName(), lib, dto.getUptime());
+
+                updateOne(USER_INSTANCES,
+                        and(exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
+                                elemMatch(COMPUTATIONAL_LIBS + "." + dto.getComputationalName(),
+                                        libCondition(lib.getGroup(), lib.getName()))),
+                        new Document(SET, values));
+            } catch (Exception e) {
+                throw new DatalabException(String.format("Could not update library %s for %s/%s",
+                        lib, dto.getExploratoryName(), dto.getComputationalName()), e);
+            }
+        }
+    }
+
+    private static Bson libCondition(String group, String name) {
+        return and(eq(LIB_GROUP, group), eq(LIB_NAME, name));
+    }
+
+    private Document addLibraryFields(LibInstallDTO lib) {
+        Document values = new Document(libraryFieldFilter(STATUS), lib.getStatus());
+        if (lib.getVersion() != null) {
+            values.append(libraryFieldFilter(LIB_VERSION), lib.getVersion());
+        }
+
+        return values;
+    }
+
+    private Document updateLibraryFields(LibInstallDTO lib, Date uptime) {
+        Document values = new Document(libraryFieldFilter(STATUS), lib.getStatus());
+        if (lib.getVersion() != null) {
+            values.append(libraryFieldFilter(LIB_VERSION), lib.getVersion());
+        }
+        if (uptime != null) {
+            values.append(libraryFieldFilter(LIB_INSTALL_DATE), uptime);
+        }
+        if (lib.getAvailableVersions() != null) {
+            values.append(libraryFieldFilter(LIB_AVAILABLE_VERSION), lib.getAvailableVersions());
+        }
+        if (lib.getAddedPackages() != null) {
+            values.append(libraryFieldFilter(LIB_ADDED_PACKAGES), lib.getAddedPackages());
+        }
+        if (lib.getErrorMessage() != null) {
+            values.append(libraryFieldFilter(LIB_ERROR_MESSAGE),
+                    DateRemoverUtil.removeDateFormErrorMessage(lib.getErrorMessage()));
+        }
+
+        return values;
+    }
+
+    private Document addComputationalLibraryFields(String computational, LibInstallDTO lib) {
+        Document values = new Document(computationalLibraryFieldFilter(computational, STATUS), lib.getStatus());
+        if (lib.getVersion() != null) {
+            values.append(computationalLibraryFieldFilter(computational, LIB_VERSION), lib.getVersion());
+        }
+
+        return values;
+    }
+
+    private Document updateComputationalLibraryFields(String computational, LibInstallDTO lib, Date uptime) {
+        Document values = new Document(computationalLibraryFieldFilter(computational, STATUS), lib.getStatus());
+        if (lib.getVersion() != null) {
+            values.append(computationalLibraryFieldFilter(computational, LIB_VERSION), lib.getVersion());
+        }
+        if (uptime != null) {
+            values.append(computationalLibraryFieldFilter(computational, LIB_INSTALL_DATE), uptime);
+        }
+        if (lib.getAvailableVersions() != null) {
+            values.append(computationalLibraryFieldFilter(computational, LIB_AVAILABLE_VERSION), lib.getAvailableVersions());
+        }
+        if (lib.getAddedPackages() != null) {
+            values.append(computationalLibraryFieldFilter(computational, LIB_ADDED_PACKAGES), lib.getAddedPackages());
+        }
+        if (lib.getErrorMessage() != null) {
+            values.append(computationalLibraryFieldFilter(computational, LIB_ERROR_MESSAGE),
+                    DateRemoverUtil.removeDateFormErrorMessage(lib.getErrorMessage()));
+        }
+
+        return values;
+    }
+
+    @SuppressWarnings("unchecked")
+    private Stream<Library> computationalLibStream(Document libsDocument) {
+        return ((List<Document>) libsDocument.getOrDefault(COMPUTATIONAL_RESOURCES, Collections.emptyList()))
+                .stream()
+                .map(d -> d.getString(COMPUTATIONAL_NAME_FIELD))
+                .flatMap(compName -> libraryStream(
+                        (Document) libsDocument.getOrDefault(COMPUTATIONAL_LIBS, new Document()),
+                        compName,
+                        compName, ResourceType.COMPUTATIONAL));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Stream<Library> libraryStream(Document libsDocument, String resourceName, String libFieldName,
+                                          ResourceType libType) {
+        return ((List<Document>) libsDocument.getOrDefault(libFieldName, Collections.emptyList()))
+                .stream()
+                .map(d -> convertFromDocument(d, Library.class))
+                .filter(library -> !Arrays.asList(LibStatus.INVALID_VERSION, LibStatus.INVALID_NAME).contains(library.getStatus()))
+                .peek(l -> l.withType(libType).withResourceName(resourceName));
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/GitCredsDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/GitCredsDAO.java
new file mode 100644
index 0000000..3b68b14
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/GitCredsDAO.java
@@ -0,0 +1,99 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.dto.exploratory.ExploratoryGitCreds;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsDTO;
+import org.bson.Document;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import static com.epam.datalab.backendapi.dao.MongoCollections.GIT_CREDS;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Projections.excludeId;
+import static com.mongodb.client.model.Projections.fields;
+import static com.mongodb.client.model.Projections.include;
+
+/**
+ * DAO for user exploratory.
+ */
+public class GitCredsDAO extends BaseDAO {
+    private static final String FIELD_GIT_CREDS = "git_creds";
+
+    /**
+     * Find and return the list of GIT credentials for user.
+     *
+     * @param user name.
+     * @return GIT credentials DTO
+     */
+    public ExploratoryGitCredsDTO findGitCreds(String user) {
+        return findGitCreds(user, false);
+    }
+
+    /**
+     * Find and return the list of GIT credentials for user.
+     *
+     * @param user          name.
+     * @param clearPassword clear user password if set to <b>true</b>.
+     * @return GIT credentials DTO
+     */
+    public ExploratoryGitCredsDTO findGitCreds(String user, boolean clearPassword) {
+        Optional<ExploratoryGitCredsDTO> opt = findOne(GIT_CREDS,
+                eq(ID, user),
+                fields(include(FIELD_GIT_CREDS), excludeId()),
+                ExploratoryGitCredsDTO.class);
+        ExploratoryGitCredsDTO creds = (opt.orElseGet(ExploratoryGitCredsDTO::new));
+        List<ExploratoryGitCreds> list = creds.getGitCreds();
+        if (clearPassword && list != null) {
+            for (ExploratoryGitCreds cred : list) {
+                cred.setPassword(null);
+            }
+        }
+
+        return creds;
+    }
+
+    /**
+     * Update the GIT credentials for user.
+     *
+     * @param user name.
+     * @param dto  GIT credentials.
+     */
+    public void updateGitCreds(String user, ExploratoryGitCredsDTO dto) {
+        List<ExploratoryGitCreds> list = findGitCreds(user).getGitCreds();
+        if (list != null && dto.getGitCreds() != null) {
+            Collections.sort(dto.getGitCreds());
+            // Restore passwords from Mongo DB.
+            for (ExploratoryGitCreds cred : dto.getGitCreds()) {
+                if (cred.getPassword() == null) {
+                    int index = Collections.binarySearch(list, cred);
+                    if (index >= 0) {
+                        cred.setPassword(list.get(index).getPassword());
+                    }
+                }
+            }
+        }
+
+        Document d = new Document(SET, convertToBson(dto).append(ID, user));
+        updateOne(GIT_CREDS, eq(ID, user), d, true);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAO.java
new file mode 100644
index 0000000..d8e8987
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAO.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.epam.datalab.dto.exploratory.LibStatus;
+import com.epam.datalab.model.exploratory.Image;
+import com.epam.datalab.model.library.Library;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface ImageExploratoryDAO {
+
+    boolean exist(String image, String project);
+
+    void save(Image image);
+
+    void updateImageFields(Image image);
+
+    List<ImageInfoRecord> getImages(String user, String dockerImage, String project, String endpoint, ImageStatus... statuses);
+
+    List<ImageInfoRecord> getImagesForProject(String project);
+
+    Optional<ImageInfoRecord> getImage(String user, String name, String project, String endpoint);
+
+    List<Library> getLibraries(String user, String imageFullName, String project, String endpoint, LibStatus status);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAOImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAOImpl.java
new file mode 100644
index 0000000..234a15e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAOImpl.java
@@ -0,0 +1,155 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.epam.datalab.dto.exploratory.LibStatus;
+import com.epam.datalab.model.exploratory.Image;
+import com.epam.datalab.model.library.Library;
+import com.google.inject.Singleton;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.in;
+import static com.mongodb.client.model.Projections.elemMatch;
+import static com.mongodb.client.model.Projections.excludeId;
+import static com.mongodb.client.model.Projections.fields;
+import static com.mongodb.client.model.Projections.include;
+
+@Singleton
+public class ImageExploratoryDAOImpl extends BaseDAO implements ImageExploratoryDAO {
+
+    private static final String LIBRARIES = "libraries";
+    private static final String IMAGE_NAME = "name";
+    private static final String IMAGE_APPLICATION = "application";
+    private static final String IMAGE_FULL_NAME = "fullName";
+    private static final String EXTERNAL_NAME = "externalName";
+    private static final String DOCKER_IMAGE = "dockerImage";
+    private static final String PROJECT = "project";
+    private static final String ENDPOINT = "endpoint";
+
+    @Override
+    public boolean exist(String image, String project) {
+        return findOne(MongoCollections.IMAGES, imageProjectCondition(image, project)).isPresent();
+    }
+
+    @Override
+    public void save(Image image) {
+        insertOne(MongoCollections.IMAGES, image);
+    }
+
+    @Override
+    public void updateImageFields(Image image) {
+        final Bson condition = userImageCondition(image.getUser(), image.getName(), image.getProject(), image.getEndpoint());
+        final Document updatedFields = getUpdatedFields(image);
+        updateOne(MongoCollections.IMAGES, condition, new Document(SET, updatedFields));
+    }
+
+    @Override
+    public List<ImageInfoRecord> getImages(String user, String dockerImage, String project, String endpoint, ImageStatus... statuses) {
+        return find(MongoCollections.IMAGES,
+                userImagesCondition(user, dockerImage, project, endpoint, statuses),
+                ImageInfoRecord.class);
+    }
+
+    @Override
+    public List<ImageInfoRecord> getImagesForProject(String project) {
+        return find(MongoCollections.IMAGES,
+                eq(PROJECT, project),
+                ImageInfoRecord.class);
+    }
+
+    @Override
+    public Optional<ImageInfoRecord> getImage(String user, String name, String project, String endpoint) {
+        return findOne(MongoCollections.IMAGES, userImageCondition(user, name, project, endpoint), ImageInfoRecord.class);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<Library> getLibraries(String user, String imageFullName, String project, String endpoint, LibStatus status) {
+        return ((List<Document>) libDocument(user, imageFullName, project, endpoint, status)
+                .orElse(emptyLibrariesDocument()).get(LIBRARIES))
+                .stream()
+                .map(d -> convertFromDocument(d, Library.class))
+                .collect(Collectors.toList());
+    }
+
+    private Optional<Document> libDocument(String user, String imageFullName, String project, String endpoint,
+                                           LibStatus status) {
+        return findOne(MongoCollections.IMAGES,
+                imageLibraryCondition(user, imageFullName, project, endpoint, status),
+                fields(include(LIBRARIES), excludeId()));
+    }
+
+    private Document emptyLibrariesDocument() {
+        return new Document(LIBRARIES, Collections.emptyList());
+    }
+
+    private Bson imageLibraryCondition(String user, String imageFullName, String project, String endpoint,
+                                       LibStatus status) {
+        return and(eq(USER, user), eq(IMAGE_NAME, imageFullName), eq(PROJECT, project), eq(ENDPOINT, endpoint),
+                elemMatch(LIBRARIES, eq(STATUS, status.name())));
+    }
+
+    private Bson userImagesCondition(String user, String dockerImage, String project, String endpoint, ImageStatus... statuses) {
+        final Bson userImagesCondition = userImagesCondition(user, project, endpoint, statuses);
+        if (Objects.nonNull(dockerImage)) {
+            return and(userImagesCondition, eq(DOCKER_IMAGE, dockerImage));
+        } else {
+            return userImagesCondition;
+        }
+
+    }
+
+    private Bson userImagesCondition(String user, String project, String endpoint, ImageStatus... statuses) {
+
+        final List<String> statusList = Arrays
+                .stream(statuses)
+                .map(ImageStatus::name)
+                .collect(Collectors.toList());
+        return and(eq(USER, user), in(STATUS, statusList), eq(PROJECT, project), eq(ENDPOINT, endpoint));
+    }
+
+
+    private Bson userImageCondition(String user, String imageName, String project, String endpoint) {
+        return and(eq(USER, user), eq(IMAGE_NAME, imageName), eq(PROJECT, project), eq(ENDPOINT, endpoint));
+    }
+
+    private Bson imageProjectCondition(String image, String project) {
+        return and(eq(IMAGE_NAME, image), eq(PROJECT, project));
+    }
+
+    private Document getUpdatedFields(Image image) {
+        return new Document(STATUS, image.getStatus().toString())
+                .append(IMAGE_FULL_NAME, image.getFullName())
+                .append(IMAGE_APPLICATION, image.getApplication())
+                .append(EXTERNAL_NAME, image.getExternalName());
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/IndexCreator.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/IndexCreator.java
new file mode 100644
index 0000000..93cfb80
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/IndexCreator.java
@@ -0,0 +1,45 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.mongodb.client.model.IndexOptions;
+import com.mongodb.client.model.Indexes;
+import io.dropwizard.lifecycle.Managed;
+
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.EXPLORATORY_NAME;
+import static com.epam.datalab.backendapi.dao.MongoCollections.USER_INSTANCES;
+
+/**
+ * Creates the indexes for mongo collections.
+ */
+public class IndexCreator extends BaseDAO implements Managed {
+    private static final String PROJECT_FIELD = "project";
+
+    @Override
+    public void start() {
+        mongoService.getCollection(USER_INSTANCES)
+                .createIndex(Indexes.ascending(USER, EXPLORATORY_NAME, PROJECT_FIELD), new IndexOptions().unique(true));
+    }
+
+    @Override
+    public void stop() {
+        //Add some functionality if necessary
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/MongoCollections.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/MongoCollections.java
new file mode 100644
index 0000000..24909f5
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/MongoCollections.java
@@ -0,0 +1,82 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+/**
+ * Names of Mongo collections.
+ */
+public class MongoCollections {
+    /**
+     * Environment settings.
+     */
+    public static final String SETTINGS = "settings";
+    /**
+     * Attempts of the user login into DataLab.
+     */
+    static final String LOGIN_ATTEMPTS = "loginAttempts";
+    /**
+     * Attempts the actions of docker.
+     */
+    static final String DOCKER_ATTEMPTS = "dockerAttempts";
+    /**
+     * User keys and credentials.
+     */
+    static final String USER_KEYS = "userKeys";
+    /**
+     * User AWS credentials.
+     */
+    public static final String USER_EDGE = "userCloudCredentials";
+    /**
+     * Instances of user.
+     */
+    public static final String USER_INSTANCES = "userInstances";
+    /**
+     * Name of shapes.
+     */
+    public static final String SHAPES = "shapes";
+    static final String USER_SETTINGS = "userSettings";
+    /* Billing data. */
+    public static final String BILLING = "billing";
+    /**
+     * User roles.
+     */
+    static final String ROLES = "roles";
+    /**
+     * GIT credentials of user.
+     */
+    public static final String GIT_CREDS = "gitCreds";
+    /**
+     * RequestId
+     */
+    static final String REQUEST_ID = "requestId";
+    /**
+     * Images
+     */
+    public static final String IMAGES = "images";
+    /**
+     * Backup
+     */
+    public static final String BACKUPS = "backup";
+
+    public static final String USER_GROUPS = "userGroups";
+
+    private MongoCollections() {
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/MongoSetting.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/MongoSetting.java
new file mode 100644
index 0000000..7b8dabd
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/MongoSetting.java
@@ -0,0 +1,107 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+/**
+ * Name of fields in the Mongo collection {@link MongoCollections#SETTINGS}.
+ */
+public enum MongoSetting {
+
+    // General properties
+    /**
+     * Base name of service.
+     */
+    SERIVICE_BASE_NAME("conf_service_base_name"),
+    /**
+     * Name of directory for user key.
+     */
+    CONF_KEY_DIRECTORY("conf_key_dir"),
+    /**
+     * Name of resource id.
+     */
+    CONF_TAG_RESOURCE_ID("conf_tag_resource_id"),
+    /**
+     * Name of OS family.
+     */
+    CONF_OS_FAMILY("conf_os_family"),
+
+    CONF_MAX_BUDGET("conf_max_budget"),
+    SSN_STORAGE_ACCOUNT_TAG_NAME("ssn_storage_account_tag_name"),
+    SHARED_STORAGE_ACCOUNT_TAG_NAME("shared_storage_account_tag_name"),
+
+    LDAP_HOSTNAME("ldap_hostname"),
+    LDAP_DN("ldap_dn"),
+    LDAP_OU("ldap_ou"),
+    LDAP_USER("ldap_service_username"),
+    LDAP_PASSWORD("ldap_service_password"),
+
+    PEERING_ID("peering_id"),
+
+
+    // AWS Related properties
+    /**
+     * Name of AWS region.
+     */
+    AWS_REGION("aws_region"),
+    /**
+     * Id of security group.
+     */
+    AWS_SECURITY_GROUPS("aws_security_groups_ids"),
+    /**
+     * Id of virtual private cloud for AWS account.
+     */
+    AWS_VPC_ID("aws_vpc_id"),
+    /**
+     * Id of virtual private cloud subnet for AWS account.
+     */
+    AWS_SUBNET_ID("aws_subnet_id"),
+    AWS_NOTEBOOK_VPC_ID("aws_notebook_vpc_id"),
+    AWS_NOTEBOOK_SUBNET_ID("aws_notebook_subnet_id"),
+    AWS_ZONE("aws_zone"),
+
+
+    // Azure related properties
+    AZURE_REGION("azure_region"),
+    AZURE_RESOURCE_GROUP_NAME("azure_resource_group_name"),
+    AZURE_SUBNET_NAME("azure_subnet_name"),
+    AZURE_VPC_NAME("azure_vpc_name"),
+    AZURE_SECURITY_GROUP_NAME("azure_security_group_name"),
+    AZURE_EDGE_INSTANCE_SIZE("edge_instance_size"),
+    SSN_INSTANCE_SIZE("ssn_instance_size"),
+    AZURE_DATA_LAKE_NAME_TAG("datalake_tag_name"),
+    AZURE_DATA_LAKE_CLIENT_ID("azure_client_id"),
+
+    // GCP related properties
+    GCP_REGION("gcp_region"),
+    GCP_ZONE("gcp_zone"),
+    GCP_SUBNET_NAME("gcp_subnet_name"),
+    GCP_PROJECT_ID("gcp_project_id"),
+    GCP_VPC_NAME("gcp_vpc_name");
+
+    private String id;
+
+    MongoSetting(String id) {
+        this.id = id;
+    }
+
+    public String getId() {
+        return id;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ProjectDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ProjectDAO.java
new file mode 100644
index 0000000..c5024af
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ProjectDAO.java
@@ -0,0 +1,59 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+public interface ProjectDAO {
+    List<ProjectDTO> getProjects();
+
+    List<ProjectDTO> getProjectsWithEndpointStatusNotIn(UserInstanceStatus... statuses);
+
+    List<ProjectDTO> getUserProjects(UserInfo userInfo, boolean active);
+
+    void create(ProjectDTO projectDTO);
+
+    void updateStatus(String projectName, ProjectDTO.Status status);
+
+    void updateEdgeStatus(String projectName, String endpoint, UserInstanceStatus status);
+
+    void updateEdgeInfo(String projectName, String endpointName, EdgeInfo edgeInfo);
+
+    Optional<ProjectDTO> get(String name);
+
+    List<ProjectDTO> getProjectsByEndpoint(String endpointName);
+
+    boolean update(ProjectDTO projectDTO);
+
+    void remove(String name);
+
+    Optional<Integer> getAllowedBudget(String project);
+
+    void updateBudget(String project, Integer budget, boolean monthlyBudget);
+
+    boolean isAnyProjectAssigned(Set<String> groups);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ProjectDAOImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ProjectDAOImpl.java
new file mode 100644
index 0000000..e3bbc0a
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ProjectDAOImpl.java
@@ -0,0 +1,190 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.BudgetDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import com.google.common.collect.Iterables;
+import com.google.inject.Inject;
+import com.mongodb.BasicDBObject;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.elemMatch;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.in;
+import static com.mongodb.client.model.Filters.not;
+
+public class ProjectDAOImpl extends BaseDAO implements ProjectDAO {
+
+    private static final String PROJECTS_COLLECTION = "Projects";
+    private static final String GROUPS = "groups";
+    private static final String ENDPOINTS = "endpoints";
+    private static final String STATUS_FIELD = "status";
+    private static final String BUDGET_FIELD = "budget";
+    private static final String VALUE_FIELD = "value";
+    private static final String MONTHLY_BUDGET_FIELD = "monthlyBudget";
+    private static final String SHARED_IMAGE_FIELD = "sharedImageEnabled";
+    private static final String ENDPOINT_STATUS_FIELD = "endpoints." + STATUS_FIELD;
+    private static final String EDGE_INFO_FIELD = "edgeInfo";
+    private static final String ENDPOINT_FIELD = "endpoints.$.";
+    private static final String ANYUSER = Pattern.quote("$anyuser");
+
+    private final UserGroupDAO userGroupDao;
+
+    @Inject
+    public ProjectDAOImpl(UserGroupDAO userGroupDao) {
+        this.userGroupDao = userGroupDao;
+    }
+
+
+    @Override
+    public List<ProjectDTO> getProjects() {
+        return find(PROJECTS_COLLECTION, ProjectDTO.class);
+    }
+
+    @Override
+    public List<ProjectDTO> getProjectsWithEndpointStatusNotIn(UserInstanceStatus... statuses) {
+        final List<String> statusList =
+                Arrays.stream(statuses)
+                        .map(UserInstanceStatus::name)
+                        .collect(Collectors.toList());
+
+        return find(PROJECTS_COLLECTION, not(in(ENDPOINT_STATUS_FIELD, statusList)), ProjectDTO.class);
+    }
+
+    @Override
+    public List<ProjectDTO> getUserProjects(UserInfo userInfo, boolean active) {
+        Stream<String> userGroups = userGroupDao.getUserGroups(userInfo.getName()).stream();
+        Stream<String> roles = userInfo.getRoles().stream();
+        final Set<String> groups = Stream.concat(userGroups, roles)
+                .collect(Collectors.toSet());
+        return find(PROJECTS_COLLECTION, userProjectCondition(groups, active), ProjectDTO.class);
+    }
+
+    @Override
+    public void create(ProjectDTO projectDTO) {
+        insertOne(PROJECTS_COLLECTION, projectDTO);
+    }
+
+    @Override
+    public void updateStatus(String projectName, ProjectDTO.Status status) {
+        updateOne(PROJECTS_COLLECTION, projectCondition(projectName),
+                new Document(SET, new Document(STATUS_FIELD, status.toString())));
+    }
+
+    @Override
+    public void updateEdgeStatus(String projectName, String endpoint, UserInstanceStatus status) {
+        BasicDBObject dbObject = new BasicDBObject();
+        dbObject.put(ENDPOINT_FIELD + STATUS_FIELD, status.name());
+        updateOne(PROJECTS_COLLECTION, projectAndEndpointCondition(projectName,
+                endpoint), new Document(SET, dbObject));
+    }
+
+    @Override
+    public void updateEdgeInfo(String projectName, String endpointName, EdgeInfo edgeInfo) {
+        BasicDBObject dbObject = new BasicDBObject();
+        dbObject.put(ENDPOINT_FIELD + STATUS_FIELD, UserInstanceStatus.RUNNING.name());
+        dbObject.put(ENDPOINT_FIELD + EDGE_INFO_FIELD, convertToBson(edgeInfo));
+        updateOne(PROJECTS_COLLECTION, projectAndEndpointCondition(projectName, endpointName), new Document(SET,
+                dbObject));
+    }
+
+    @Override
+    public Optional<ProjectDTO> get(String name) {
+        return findOne(PROJECTS_COLLECTION, projectCondition(name), ProjectDTO.class);
+    }
+
+    @Override
+    public List<ProjectDTO> getProjectsByEndpoint(String endpointName) {
+        return find(PROJECTS_COLLECTION, elemMatch(ENDPOINTS, eq("name", endpointName)), ProjectDTO.class);
+    }
+
+    @Override
+    public boolean update(ProjectDTO projectDTO) {
+        BasicDBObject updateProject = new BasicDBObject();
+        updateProject.put(GROUPS, projectDTO.getGroups());
+        updateProject.put(ENDPOINTS,
+                projectDTO.getEndpoints().stream().map(this::convertToBson).collect(Collectors.toList()));
+        updateProject.put(SHARED_IMAGE_FIELD, projectDTO.isSharedImageEnabled());
+        return updateOne(PROJECTS_COLLECTION, projectCondition(projectDTO.getName()),
+                new Document(SET, updateProject)).getMatchedCount() > 0L;
+    }
+
+    @Override
+    public void remove(String name) {
+        deleteOne(PROJECTS_COLLECTION, projectCondition(name));
+    }
+
+    @Override
+    public Optional<Integer> getAllowedBudget(String project) {
+        return get(project)
+                .flatMap(p -> Optional.ofNullable(p.getBudget())
+                        .map(BudgetDTO::getValue));
+    }
+
+    @Override
+    public void updateBudget(String project, Integer budget, boolean monthlyBudget) {
+        BasicDBObject updateBudget = new BasicDBObject();
+        updateBudget.put(VALUE_FIELD, budget);
+        updateBudget.put(MONTHLY_BUDGET_FIELD, monthlyBudget);
+        updateOne(PROJECTS_COLLECTION, projectCondition(project), new Document(SET, new Document(BUDGET_FIELD, updateBudget)));
+    }
+
+    @Override
+    public boolean isAnyProjectAssigned(Set<String> groups) {
+        final String groupsRegex = !groups.isEmpty() ? String.join("|", groups) + "|" + ANYUSER : ANYUSER;
+        return !Iterables.isEmpty(find(PROJECTS_COLLECTION, elemMatch(GROUPS, regexCaseInsensitive(groupsRegex))));
+    }
+
+    private Bson projectCondition(String name) {
+        return eq("name", name);
+    }
+
+    private Bson userProjectCondition(Set<String> groups, boolean active) {
+        final String groupsRegex = !groups.isEmpty() ? String.join("|", groups) + "|" + ANYUSER : ANYUSER;
+        if (active) {
+            return and(elemMatch(GROUPS, regexCaseInsensitive(groupsRegex)),
+                    eq(ENDPOINT_STATUS_FIELD, UserInstanceStatus.RUNNING.name()));
+        }
+        return elemMatch(GROUPS, regexCaseInsensitive(groupsRegex));
+    }
+
+    private Bson projectAndEndpointCondition(String projectName, String endpointName) {
+        return and(eq("name", projectName), eq("endpoints.name", endpointName));
+    }
+
+    private Document regexCaseInsensitive(String values) {
+        return new Document("$regex",
+                "^(" + values + ")$").append("$options", "i");
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/RequestIdDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/RequestIdDAO.java
new file mode 100644
index 0000000..aa83887
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/RequestIdDAO.java
@@ -0,0 +1,68 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.domain.RequestIdDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.mongodb.client.model.Updates;
+import com.mongodb.client.result.DeleteResult;
+import org.bson.Document;
+
+import java.util.Date;
+import java.util.Optional;
+
+import static com.epam.datalab.backendapi.dao.MongoCollections.REQUEST_ID;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.lt;
+
+/**
+ * DAO for request id.
+ */
+public class RequestIdDAO extends BaseDAO {
+    private static final String EXPIRATION_TIME = "expirationTime";
+
+    public RequestIdDTO get(String id) {
+        Optional<RequestIdDTO> opt = findOne(REQUEST_ID, eq(ID, id), RequestIdDTO.class);
+        if (!opt.isPresent()) {
+            throw new DatalabException("Request id " + id + " not found.");
+        }
+        return opt.get();
+    }
+
+    public void put(RequestIdDTO requestId) {
+        getCollection(REQUEST_ID)
+                .insertOne(convertToBson(requestId));
+    }
+
+    public void delete(String id) {
+        getCollection(REQUEST_ID).deleteOne(eq(ID, id));
+    }
+
+    public void resetExpirationTime() {
+        Date time = new Date();
+        getCollection(REQUEST_ID).updateMany(new Document(), Updates.set(EXPIRATION_TIME, time));
+    }
+
+    public long removeExpired() {
+        DeleteResult result = getCollection(REQUEST_ID)
+                .deleteMany(lt(EXPIRATION_TIME, new Date()));
+        return result.getDeletedCount();
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SchedulerJobDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SchedulerJobDAO.java
new file mode 100644
index 0000000..19ebeb1
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SchedulerJobDAO.java
@@ -0,0 +1,248 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.model.scheduler.SchedulerJobData;
+import com.google.inject.Singleton;
+import com.mongodb.client.FindIterable;
+import com.mongodb.client.model.Filters;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.epam.datalab.backendapi.dao.ComputationalDAO.COMPUTATIONAL_NAME;
+import static com.epam.datalab.backendapi.dao.ComputationalDAO.IMAGE;
+import static com.epam.datalab.backendapi.dao.ComputationalDAO.PROJECT;
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.COMPUTATIONAL_RESOURCES;
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.EXPLORATORY_NAME;
+import static com.epam.datalab.backendapi.dao.ExploratoryDAO.exploratoryCondition;
+import static com.epam.datalab.backendapi.dao.MongoCollections.USER_INSTANCES;
+import static com.epam.datalab.dto.base.DataEngineType.fromDockerImageName;
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.exists;
+import static com.mongodb.client.model.Filters.in;
+import static com.mongodb.client.model.Filters.lte;
+import static com.mongodb.client.model.Filters.ne;
+import static com.mongodb.client.model.Filters.or;
+import static com.mongodb.client.model.Projections.excludeId;
+import static com.mongodb.client.model.Projections.fields;
+import static com.mongodb.client.model.Projections.include;
+import static java.util.stream.Collectors.toList;
+
+/**
+ * DAO for user's scheduler jobs.
+ */
+@Slf4j
+@Singleton
+public class SchedulerJobDAO extends BaseDAO {
+
+    static final String SCHEDULER_DATA = "scheduler_data";
+    private static final String CONSIDER_INACTIVITY_FLAG = SCHEDULER_DATA + ".consider_inactivity";
+    public static final String TIMEZONE_PREFIX = "UTC";
+    private static final String LAST_ACTIVITY = "last_activity";
+    private static final String CHECK_INACTIVITY_REQUIRED = "check_inactivity_required";
+    private static final String CHECK_INACTIVITY_FLAG = SCHEDULER_DATA + "." + CHECK_INACTIVITY_REQUIRED;
+
+
+    public SchedulerJobDAO() {
+        log.info("{} is initialized", getClass().getSimpleName());
+    }
+
+    /**
+     * Returns condition for search scheduler for exploratory which is not null.
+     *
+     * @return Bson condition.
+     */
+    private Bson schedulerNotNullCondition() {
+        return and(exists(SCHEDULER_DATA), ne(SCHEDULER_DATA, null));
+    }
+
+    /**
+     * Finds and returns the info of user's single scheduler job by exploratory name.
+     *
+     * @param user            user name.
+     * @param project         project name
+     * @param exploratoryName the name of exploratory.
+     * @return scheduler job data.
+     */
+    public Optional<SchedulerJobDTO> fetchSingleSchedulerJobByUserAndExploratory(String user, String project, String exploratoryName) {
+        return findOne(USER_INSTANCES,
+                and(exploratoryCondition(user, exploratoryName, project), schedulerNotNullCondition()),
+                fields(include(SCHEDULER_DATA), excludeId()))
+                .map(d -> convertFromDocument((Document) d.get(SCHEDULER_DATA), SchedulerJobDTO.class));
+    }
+
+    /**
+     * Finds and returns the info of user's single scheduler job for computational resource.
+     *
+     * @param user              user name.
+     * @param project           project name
+     * @param exploratoryName   the name of exploratory.
+     * @param computationalName the name of computational resource.
+     * @return scheduler job data.
+     */
+
+    @SuppressWarnings("unchecked")
+    public Optional<SchedulerJobDTO> fetchSingleSchedulerJobForCluster(String user, String project, String exploratoryName,
+                                                                       String computationalName) {
+        return findOne(USER_INSTANCES,
+                exploratoryCondition(user, exploratoryName, project),
+                fields(include(COMPUTATIONAL_RESOURCES), excludeId()))
+                .map(d -> (List<Document>) d.get(COMPUTATIONAL_RESOURCES))
+                .map(list -> list.stream().filter(d -> d.getString(COMPUTATIONAL_NAME).equals(computationalName))
+                        .findAny().orElse(new Document()))
+                .map(d -> (Document) d.get(SCHEDULER_DATA))
+                .map(d -> convertFromDocument(d, SchedulerJobDTO.class));
+    }
+
+    /**
+     * Finds and returns the list of all scheduler jobs for starting/stopping/terminating exploratories regarding to
+     * parameter passed.
+     *
+     * @param status 'running' value for starting exploratory, 'stopped' - for stopping and 'terminated' -
+     *               for
+     *               terminating.
+     * @return list of scheduler jobs.
+     */
+    public List<SchedulerJobData> getExploratorySchedulerDataWithStatus(UserInstanceStatus status) {
+        FindIterable<Document> userInstances = userInstancesWithScheduler(eq(STATUS, status.toString()));
+
+        return stream(userInstances).map(d -> convertFromDocument(d, SchedulerJobData.class))
+                .collect(toList());
+    }
+
+    public List<SchedulerJobData> getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(UserInstanceStatus status,
+                                                                                                  Date lastActivity) {
+        return stream(find(USER_INSTANCES,
+                and(
+                        eq(STATUS, status.toString()),
+                        schedulerNotNullCondition(),
+                        or(and(eq(CONSIDER_INACTIVITY_FLAG, true),
+                                or(eq(COMPUTATIONAL_RESOURCES, Collections.emptyList()),
+                                        and(ne(COMPUTATIONAL_RESOURCES, Collections.emptyList()),
+                                                Filters.elemMatch(COMPUTATIONAL_RESOURCES,
+                                                        lte(LAST_ACTIVITY, lastActivity))))),
+                                eq(CONSIDER_INACTIVITY_FLAG, false)
+                        )
+                ),
+                fields(excludeId(), include(USER, PROJECT, EXPLORATORY_NAME, SCHEDULER_DATA))))
+                .map(d -> convertFromDocument(d, SchedulerJobData.class))
+                .collect(toList());
+    }
+
+    public List<SchedulerJobData> getExploratorySchedulerDataWithOneOfStatus(UserInstanceStatus... statuses) {
+        FindIterable<Document> userInstances = userInstancesWithScheduler(in(STATUS,
+                Arrays.stream(statuses).map(UserInstanceStatus::toString).collect(toList())));
+
+        return stream(userInstances).map(d -> convertFromDocument(d, SchedulerJobData.class))
+                .collect(toList());
+    }
+
+    public List<SchedulerJobData> getComputationalSchedulerDataWithOneOfStatus(UserInstanceStatus exploratoryStatus,
+                                                                               DataEngineType dataEngineType,
+                                                                               UserInstanceStatus... statuses) {
+        return stream(computationalResourcesWithScheduler(exploratoryStatus))
+                .map(doc -> computationalSchedulerDataStream(doc, dataEngineType, statuses))
+                .flatMap(Function.identity())
+                .collect(toList());
+    }
+
+    public List<SchedulerJobData> getComputationalSchedulerDataWithOneOfStatus(UserInstanceStatus exploratoryStatus,
+                                                                               UserInstanceStatus... statuses) {
+        return stream(computationalResourcesWithScheduler(exploratoryStatus))
+                .map(doc -> computationalSchedulerData(doc, statuses).map(compResource -> toSchedulerData(doc,
+                        compResource)))
+                .flatMap(Function.identity())
+                .collect(toList());
+    }
+
+    private FindIterable<Document> computationalResourcesWithScheduler(UserInstanceStatus exploratoryStatus) {
+        final Bson computationalSchedulerCondition = Filters.elemMatch(COMPUTATIONAL_RESOURCES,
+                and(schedulerNotNullCondition()));
+        return find(USER_INSTANCES,
+                and(eq(STATUS, exploratoryStatus.toString()), computationalSchedulerCondition),
+                fields(excludeId(), include(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_RESOURCES)));
+    }
+
+    public void removeScheduler(String user, String exploratory) {
+        updateOne(USER_INSTANCES, and(eq(USER, user), eq(EXPLORATORY_NAME, exploratory)),
+                unset(SCHEDULER_DATA, StringUtils.EMPTY));
+    }
+
+    public void removeScheduler(String user, String exploratory, String computational) {
+        updateOne(USER_INSTANCES, and(eq(USER, user), eq(EXPLORATORY_NAME, exploratory),
+                Filters.elemMatch(COMPUTATIONAL_RESOURCES, eq(COMPUTATIONAL_NAME, computational))),
+                unset(COMPUTATIONAL_RESOURCES + ".$." + SCHEDULER_DATA, StringUtils.EMPTY));
+    }
+
+    private FindIterable<Document> userInstancesWithScheduler(Bson statusCondition) {
+        return find(USER_INSTANCES,
+                and(
+                        statusCondition,
+                        schedulerNotNullCondition(), eq(CHECK_INACTIVITY_FLAG, false)
+                ),
+                fields(excludeId(), include(USER, EXPLORATORY_NAME, PROJECT, SCHEDULER_DATA)));
+    }
+
+    private Stream<SchedulerJobData> computationalSchedulerDataStream(Document doc, DataEngineType computationalType,
+                                                                      UserInstanceStatus... computationalStatuses) {
+        return computationalSchedulerData(doc, computationalStatuses)
+                .filter(compResource -> fromDockerImageName(compResource.getString(IMAGE)) == computationalType)
+                .map(compResource -> toSchedulerData(doc, compResource));
+    }
+
+    private SchedulerJobData toSchedulerData(Document userInstanceDocument, Document compResource) {
+        final String user = userInstanceDocument.getString(USER);
+        final String project = userInstanceDocument.getString(PROJECT);
+        final String exploratoryName = userInstanceDocument.getString(EXPLORATORY_NAME);
+        final String computationalName = compResource.getString(COMPUTATIONAL_NAME);
+        final SchedulerJobDTO schedulerData = convertFromDocument((Document) compResource.get(SCHEDULER_DATA),
+                SchedulerJobDTO.class);
+        return new SchedulerJobData(user, exploratoryName, computationalName, project, schedulerData);
+    }
+
+    @SuppressWarnings("unchecked")
+    private Stream<Document> computationalSchedulerData(Document doc, UserInstanceStatus... computationalStatuses) {
+        final Set<String> statusSet = Arrays.stream(computationalStatuses)
+                .map(UserInstanceStatus::toString)
+                .collect(Collectors.toSet());
+        return ((List<Document>) doc.get(COMPUTATIONAL_RESOURCES))
+                .stream()
+                .filter(compResource -> Objects.nonNull(compResource.get(SCHEDULER_DATA)) &&
+                        statusSet.contains(compResource.getString(STATUS)));
+    }
+}
+
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SecurityDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SecurityDAO.java
new file mode 100644
index 0000000..85e836e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SecurityDAO.java
@@ -0,0 +1,118 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.mongodb.client.FindIterable;
+import com.mongodb.client.model.Projections;
+import org.bson.Document;
+import org.keycloak.representations.AccessTokenResponse;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.backendapi.dao.MongoCollections.ROLES;
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.gte;
+import static com.mongodb.client.model.Filters.ne;
+import static com.mongodb.client.model.Projections.exclude;
+import static com.mongodb.client.model.Projections.fields;
+import static com.mongodb.client.model.Projections.include;
+
+/**
+ * DAO write the attempt of user login into DataLab.
+ */
+@Singleton
+public class SecurityDAO extends BaseDAO {
+    private static final String SECURITY_COLLECTION = "security";
+    private static final String TOKEN_RESPONSE = "tokenResponse";
+    private static final String LAST_ACCESS = "last_access";
+
+    @Inject
+    private SelfServiceApplicationConfiguration conf;
+
+    /**
+     * Return the roles or throw exception if roles collection does not exists.
+     */
+    public FindIterable<Document> getRoles() {
+        if (!collectionExists(ROLES)) {
+            throw new DatalabException("Collection \"" + ROLES + "\" does not exists.");
+        }
+        return find(ROLES, ne(ID, "_Example"), fields(exclude("description")));
+    }
+
+    public Map<String, Set<String>> getGroups() {
+        return stream(find("userGroups"))
+                .collect(Collectors.toMap(d -> d.getString(ID).toLowerCase(), this::toUsers));
+
+    }
+
+    public void saveUser(String userName, AccessTokenResponse accessTokenResponse) {
+        updateOne(SECURITY_COLLECTION, eq(ID, userName),
+                new Document(SET,
+                        new Document()
+                                .append(ID, userName)
+                                .append("created", new Date())
+                                .append(LAST_ACCESS, new Date())
+                                .append(TOKEN_RESPONSE, convertToBson(accessTokenResponse))),
+                true);
+    }
+
+    public void updateUser(String userName, AccessTokenResponse accessTokenResponse) {
+        updateOne(SECURITY_COLLECTION, eq(ID, userName),
+                new Document(SET,
+                        new Document()
+                                .append(ID, userName)
+                                .append(LAST_ACCESS, new Date())
+                                .append(TOKEN_RESPONSE, convertToBson(accessTokenResponse))));
+    }
+
+    public Optional<UserInfo> getUser(String token) {
+        return Optional.ofNullable(mongoService.getCollection(SECURITY_COLLECTION)
+                .findOneAndUpdate(and(eq(TOKEN_RESPONSE + ".access_token", token), gte(LAST_ACCESS,
+                        new Date(new Date().getTime() - conf.getInactiveUserTimeoutMillSec()))), new Document("$set",
+                        new Document(LAST_ACCESS, new Date()))))
+                .map(d -> new UserInfo(d.getString(ID), token));
+    }
+
+
+    public Optional<AccessTokenResponse> getTokenResponse(String user) {
+        return findOne(SECURITY_COLLECTION, eq(ID, user), Projections.fields(include(TOKEN_RESPONSE)))
+                .map(d -> convertFromDocument((Document) d.get(TOKEN_RESPONSE), AccessTokenResponse.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Set<String> toUsers(Document d) {
+        final Object users = d.get("users");
+        return users == null ? Collections.emptySet() :
+                new HashSet<>(((List<String>) users).stream().map(String::toLowerCase).collect(Collectors.toList()));
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SettingsDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SettingsDAO.java
new file mode 100644
index 0000000..512ba0b
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SettingsDAO.java
@@ -0,0 +1,424 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.exceptions.DatalabException;
+import com.mongodb.client.model.UpdateOptions;
+import org.apache.commons.lang3.StringUtils;
+import org.bson.Document;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.backendapi.dao.MongoCollections.SETTINGS;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AWS_NOTEBOOK_SUBNET_ID;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AWS_NOTEBOOK_VPC_ID;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AWS_REGION;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AWS_SECURITY_GROUPS;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AWS_SUBNET_ID;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AWS_VPC_ID;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AWS_ZONE;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AZURE_DATA_LAKE_CLIENT_ID;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AZURE_DATA_LAKE_NAME_TAG;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AZURE_EDGE_INSTANCE_SIZE;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AZURE_REGION;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AZURE_RESOURCE_GROUP_NAME;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AZURE_SECURITY_GROUP_NAME;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AZURE_SUBNET_NAME;
+import static com.epam.datalab.backendapi.dao.MongoSetting.AZURE_VPC_NAME;
+import static com.epam.datalab.backendapi.dao.MongoSetting.CONF_KEY_DIRECTORY;
+import static com.epam.datalab.backendapi.dao.MongoSetting.CONF_MAX_BUDGET;
+import static com.epam.datalab.backendapi.dao.MongoSetting.CONF_OS_FAMILY;
+import static com.epam.datalab.backendapi.dao.MongoSetting.CONF_TAG_RESOURCE_ID;
+import static com.epam.datalab.backendapi.dao.MongoSetting.GCP_PROJECT_ID;
+import static com.epam.datalab.backendapi.dao.MongoSetting.GCP_REGION;
+import static com.epam.datalab.backendapi.dao.MongoSetting.GCP_SUBNET_NAME;
+import static com.epam.datalab.backendapi.dao.MongoSetting.GCP_VPC_NAME;
+import static com.epam.datalab.backendapi.dao.MongoSetting.GCP_ZONE;
+import static com.epam.datalab.backendapi.dao.MongoSetting.LDAP_DN;
+import static com.epam.datalab.backendapi.dao.MongoSetting.LDAP_HOSTNAME;
+import static com.epam.datalab.backendapi.dao.MongoSetting.LDAP_OU;
+import static com.epam.datalab.backendapi.dao.MongoSetting.LDAP_PASSWORD;
+import static com.epam.datalab.backendapi.dao.MongoSetting.LDAP_USER;
+import static com.epam.datalab.backendapi.dao.MongoSetting.PEERING_ID;
+import static com.epam.datalab.backendapi.dao.MongoSetting.SERIVICE_BASE_NAME;
+import static com.epam.datalab.backendapi.dao.MongoSetting.SHARED_STORAGE_ACCOUNT_TAG_NAME;
+import static com.epam.datalab.backendapi.dao.MongoSetting.SSN_INSTANCE_SIZE;
+import static com.epam.datalab.backendapi.dao.MongoSetting.SSN_STORAGE_ACCOUNT_TAG_NAME;
+import static com.mongodb.client.model.Filters.eq;
+import static org.apache.commons.lang3.StringUtils.EMPTY;
+
+/**
+ * Stores the environment settings.
+ */
+public class SettingsDAO extends BaseDAO {
+	private static final String VALUE = "value";
+
+	/**
+	 * Returns the base name of service.
+	 */
+	public String getServiceBaseName() {
+		return getSetting(SERIVICE_BASE_NAME);
+	}
+
+	public void setServiceBaseName(String sbn) {
+		setSetting(SERIVICE_BASE_NAME, sbn);
+	}
+
+	/**
+	 * Returns the name of OS family.
+	 */
+	public String getConfOsFamily() {
+		return getSetting(CONF_OS_FAMILY);
+	}
+
+	public void setConfOsFamily(String osFamily) {
+		setSetting(CONF_OS_FAMILY, osFamily);
+	}
+
+	/**
+	 * Returns the name of directory for user key.
+	 */
+	public String getConfKeyDir() {
+		return getSetting(CONF_KEY_DIRECTORY);
+	}
+
+	public void setConfKeyDir(String confKeyDir) {
+		setSetting(CONF_KEY_DIRECTORY, confKeyDir);
+	}
+
+	/**
+	 * Returns the name of tag for resource id.
+	 */
+	public String getConfTagResourceId() {
+		return getSetting(CONF_TAG_RESOURCE_ID);
+	}
+
+	public void setConfTagResourceId(String confTagResourceId) {
+		setSetting(CONF_TAG_RESOURCE_ID, confTagResourceId);
+	}
+
+	public Optional<Integer> getMaxBudget() {
+		return getOptionalSetting(CONF_MAX_BUDGET)
+				.map(Integer::valueOf);
+
+	}
+
+	public String getAwsZone() {
+		return getSetting(AWS_ZONE);
+	}
+
+	public void setAwsZone(String awsZone) {
+		setSetting(AWS_ZONE, awsZone);
+	}
+
+	public String getLdapHost() {
+		return getSetting(LDAP_HOSTNAME);
+	}
+
+	public void setLdapHost(String ldapHost) {
+		setSetting(LDAP_HOSTNAME, ldapHost);
+	}
+
+	public String getLdapOu() {
+		return getSetting(LDAP_OU);
+	}
+
+	public void setLdapOu(String ldapOu) {
+		setSetting(LDAP_OU, ldapOu);
+	}
+
+	public String getLdapDn() {
+		return getSetting(LDAP_DN);
+	}
+
+	public void setLdapDn(String ldapDn) {
+		setSetting(LDAP_DN, ldapDn);
+	}
+
+	public String getLdapUser() {
+		return getSetting(LDAP_USER);
+	}
+
+	public void setLdapUser(String user) {
+		setSetting(LDAP_USER, user);
+	}
+
+	public String getLdapPassword() {
+		return getSetting(LDAP_PASSWORD);
+	}
+
+	public void setLdapPassword(String ldapPassword) {
+		setSetting(LDAP_PASSWORD, ldapPassword);
+	}
+
+	/**
+	 * Returns the name of AWS region.
+	 */
+	public String getAwsRegion() {
+		return getSetting(AWS_REGION);
+	}
+
+	public void setAwsRegion(String awsRegion) {
+		setSetting(AWS_REGION, awsRegion);
+	}
+
+	/**
+	 * Returns the id of security group.
+	 */
+	public String getAwsSecurityGroups() {
+		return getSetting(AWS_SECURITY_GROUPS);
+	}
+
+	public void setAwsSecurityGroups(String awsSecurityGroups) {
+		setSetting(AWS_SECURITY_GROUPS, awsSecurityGroups);
+	}
+
+	/**
+	 * Returns the id of virtual private cloud for AWS account.
+	 */
+	public String getAwsVpcId() {
+		return getSetting(AWS_VPC_ID);
+	}
+
+	public void setAwsVpcId(String awsVpcId) {
+		setSetting(AWS_VPC_ID, awsVpcId);
+	}
+
+	/**
+	 * Returns the id of virtual private cloud subnet for AWS account.
+	 */
+	public void setAwsSubnetId(String awsSubnetId) {
+		setSetting(AWS_SUBNET_ID, awsSubnetId);
+	}
+
+	public String getAwsSubnetId() {
+		return getSetting(AWS_SUBNET_ID);
+	}
+
+	public String getAwsNotebookVpcId() {
+		return getSetting(AWS_NOTEBOOK_VPC_ID);
+	}
+
+	public void setSsnStorageAccountTagName(String ssnStorageAccountTagName) {
+		setSetting(SSN_STORAGE_ACCOUNT_TAG_NAME, ssnStorageAccountTagName);
+	}
+
+	public String getSsnStorageAccountTagName() {
+		return getSetting(SSN_STORAGE_ACCOUNT_TAG_NAME);
+	}
+
+	public void setSharedStorageAccountTagName(String sharedStorageAccountTagName) {
+		setSetting(SHARED_STORAGE_ACCOUNT_TAG_NAME, sharedStorageAccountTagName);
+	}
+
+	public String getSharedStorageAccountTagName() {
+		return getSetting(SHARED_STORAGE_ACCOUNT_TAG_NAME);
+	}
+
+	public void setPeeringId(String peeringId) {
+		setSetting(PEERING_ID, peeringId);
+	}
+
+	public void setAwsNotebookVpcId(String awsNotebookVpcId) {
+		setSetting(AWS_NOTEBOOK_VPC_ID, awsNotebookVpcId);
+	}
+
+	public String getAwsNotebookSubnetId() {
+		return getSetting(AWS_NOTEBOOK_SUBNET_ID);
+	}
+
+	public void setAwsNotebookSubnetId(String awsNotebookSubnetId) {
+		setSetting(AWS_NOTEBOOK_SUBNET_ID, awsNotebookSubnetId);
+	}
+
+	public String getAzureRegion() {
+		return getSetting(AZURE_REGION);
+	}
+
+	public String getAzureResourceGroupName() {
+		return getSetting(AZURE_RESOURCE_GROUP_NAME);
+	}
+
+	public String getAzureSubnetName() {
+		return getSetting(AZURE_SUBNET_NAME);
+	}
+
+	public String getAzureVpcName() {
+		return getSetting(AZURE_VPC_NAME);
+	}
+
+	public String getAzureSecurityGroupName() {
+		return getSetting(AZURE_SECURITY_GROUP_NAME);
+	}
+
+	public String getAzureEdgeInstanceSize() {
+		return getSetting(AZURE_EDGE_INSTANCE_SIZE);
+	}
+
+	public String getSsnInstanceSize() {
+		return getSetting(SSN_INSTANCE_SIZE);
+	}
+
+	public String getAzureDataLakeNameTag() {
+		return getSetting(AZURE_DATA_LAKE_NAME_TAG, "");
+	}
+
+	public boolean isAzureDataLakeEnabled() {
+		String dataLakeTagName = getAzureDataLakeNameTag();
+		return dataLakeTagName != null && !dataLakeTagName.isEmpty();
+	}
+
+	public String getAzureDataLakeClientId() {
+		return getSetting(AZURE_DATA_LAKE_CLIENT_ID);
+	}
+
+	public void setAzureRegion(String region) {
+		setSetting(AZURE_REGION, region);
+	}
+
+	public void setAzureResourceGroupName(String resourceGroupName) {
+		setSetting(AZURE_RESOURCE_GROUP_NAME, resourceGroupName);
+	}
+
+	public void setAzureSubnetName(String subnetName) {
+		setSetting(AZURE_SUBNET_NAME, subnetName);
+	}
+
+	public void setAzureVpcName(String vpcName) {
+		setSetting(AZURE_VPC_NAME, vpcName);
+	}
+
+	public void setAzureSecurityGroupName(String securityGroupName) {
+		setSetting(AZURE_SECURITY_GROUP_NAME, securityGroupName);
+	}
+
+	public void setAzureEdgeInstanceSize(String azureEdgeInstanceSize) {
+		setSetting(AZURE_EDGE_INSTANCE_SIZE, azureEdgeInstanceSize);
+	}
+
+	public void setSsnInstanceSize(String ssnInstanceSize) {
+		setSetting(SSN_INSTANCE_SIZE, ssnInstanceSize);
+	}
+
+	public void setAzureDataLakeNameTag(String dataLakeNameTag) {
+		setSetting(AZURE_DATA_LAKE_NAME_TAG, dataLakeNameTag);
+	}
+
+	public void setAzureDataLakeClientId(String dataLakeClientId) {
+		setSetting(AZURE_DATA_LAKE_CLIENT_ID, dataLakeClientId);
+	}
+
+	public String getGcpRegion() {
+		return getSetting(GCP_REGION);
+	}
+
+	public void setGcpRegion(String region) {
+		setSetting(GCP_REGION, region);
+	}
+
+	public String getGcpZone() {
+		return getSetting(GCP_ZONE);
+	}
+
+	public void setGcpZone(String zone) {
+		setSetting(GCP_ZONE, zone);
+	}
+
+	public String getGcpSubnetName() {
+		return getSetting(GCP_SUBNET_NAME);
+	}
+
+	public void setGcpSubnetName(String subnet) {
+		setSetting(GCP_SUBNET_NAME, subnet);
+	}
+
+	public String getGcpProjectId() {
+		return getSetting(GCP_PROJECT_ID);
+	}
+
+	public void setGcpProjectId(String projectId) {
+		setSetting(GCP_PROJECT_ID, projectId);
+	}
+
+	public String getGcpVpcName() {
+		return getSetting(GCP_VPC_NAME);
+	}
+
+	public void setGcpVpcName(String vpcName) {
+		setSetting(GCP_VPC_NAME, vpcName);
+	}
+
+	public void setMaxBudget(Long budget) {
+		setSetting(CONF_MAX_BUDGET, budget.toString());
+	}
+
+	public void removeSetting(MongoSetting setting) {
+		getCollection(SETTINGS).deleteOne(eq(ID, setting.getId()));
+	}
+
+	public Map<String, Object> getSettings() {
+		return stream(getCollection(SETTINGS).find())
+				.collect(Collectors.toMap(d -> d.getString(ID), d -> d.get(VALUE)));
+	}
+
+	/**
+	 * Returns the value of property from Mongo database.
+	 *
+	 * @param setting the name of property.
+	 */
+	private String getSetting(MongoSetting setting) {
+		Document d = settingDocument(setting);
+		if (d == null) {
+			throw new DatalabException("Setting property " + setting + " not found");
+		}
+		return d.getOrDefault(VALUE, EMPTY).toString();
+	}
+
+	private Optional<String> getOptionalSetting(MongoSetting setting) {
+		Document d = settingDocument(setting);
+		return Optional.ofNullable(d).map(doc -> doc.getString(VALUE));
+	}
+
+	private Document settingDocument(MongoSetting setting) {
+		return mongoService
+				.getCollection(SETTINGS)
+				.find(eq(ID, setting.getId()))
+				.first();
+	}
+
+	private void setSetting(MongoSetting mongoSetting, String value) {
+		if (StringUtils.isNotEmpty(value)) {
+			mongoService.getCollection(SETTINGS)
+					.updateOne(eq(ID, mongoSetting.getId()), new Document("$set", new Document(VALUE, value)),
+							new UpdateOptions().upsert(true));
+		}
+	}
+
+
+	private String getSetting(MongoSetting setting, String defaultValue) {
+		Document d = settingDocument(setting);
+		if (d == null) {
+			return defaultValue;
+		}
+		return d.getOrDefault(VALUE, defaultValue).toString();
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAO.java
new file mode 100644
index 0000000..1411bf9
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAO.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.datalab.backendapi.dao;
+
+import java.util.Set;
+
+public interface UserGroupDAO {
+    void addUsers(String group, Set<String> users);
+
+    void updateUsers(String group, Set<String> users);
+
+    void removeGroup(String groupId);
+
+    Set<String> getUserGroups(String user);
+
+    Set<String> getUsers(String group);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAOImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAOImpl.java
new file mode 100644
index 0000000..4fa0488
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAOImpl.java
@@ -0,0 +1,68 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.inject.Singleton;
+import org.bson.Document;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.backendapi.dao.MongoCollections.USER_GROUPS;
+import static com.mongodb.client.model.Filters.elemMatch;
+import static com.mongodb.client.model.Filters.eq;
+
+@Singleton
+public class UserGroupDAOImpl extends BaseDAO implements UserGroupDAO {
+
+    private static final String USERS_FIELD = "users";
+
+    @Override
+    public void addUsers(String group, Set<String> users) {
+        updateOne(USER_GROUPS, eq(ID, group), addToSet(USERS_FIELD, users), true);
+    }
+
+    @Override
+    public void updateUsers(String group, Set<String> users) {
+        updateOne(USER_GROUPS, eq(ID, group), new Document(SET, new Document(USERS_FIELD, users)), true);
+    }
+
+    @Override
+    public void removeGroup(String groupId) {
+        deleteOne(USER_GROUPS, eq(ID, groupId));
+    }
+
+    @Override
+    public Set<String> getUserGroups(String user) {
+        return stream(find(USER_GROUPS, elemMatch(USERS_FIELD, new Document("$regex", "^" + user + "$")
+                .append("$options", "i"))))
+                .map(document -> document.getString(ID))
+                .collect(Collectors.toSet());
+    }
+
+    @Override
+    public Set<String> getUsers(String group) {
+        return new HashSet<>(findOne(USER_GROUPS, eq(ID, group))
+                .map(document -> (List<String>) document.get(USERS_FIELD))
+                .orElseThrow(() -> new DatalabException(String.format("Group %s not found", group))));
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAO.java
new file mode 100644
index 0000000..31d4b2c
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAO.java
@@ -0,0 +1,51 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.resources.dto.UserGroupDto;
+import com.epam.datalab.backendapi.resources.dto.UserRoleDto;
+import com.epam.datalab.cloud.CloudProvider;
+
+import java.util.List;
+import java.util.Set;
+
+public interface UserRoleDAO {
+    List<UserRoleDto> findAll();
+
+    void insert(UserRoleDto dto);
+
+    void insert(List<UserRoleDto> roles);
+
+    boolean update(UserRoleDto dto);
+
+    void updateMissingRoles(CloudProvider cloudProvider);
+
+    boolean addGroupToRole(Set<String> groups, Set<String> roleIds);
+
+    void removeGroupWhenRoleNotIn(String group, Set<String> roleIds);
+
+    void removeUnnecessaryRoles(CloudProvider cloudProviderToBeRemoved, List<CloudProvider> remainingProviders);
+
+    void remove(String roleId);
+
+    boolean removeGroup(String groupId);
+
+    List<UserGroupDto> aggregateRolesByGroup();
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAOImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAOImpl.java
new file mode 100644
index 0000000..d6e649d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAOImpl.java
@@ -0,0 +1,215 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.resources.dto.UserGroupDto;
+import com.epam.datalab.backendapi.resources.dto.UserRoleDto;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.exceptions.DatalabException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Singleton;
+import com.mongodb.client.model.BsonField;
+import com.mongodb.client.result.UpdateResult;
+import lombok.extern.slf4j.Slf4j;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.epam.datalab.backendapi.dao.MongoCollections.USER_GROUPS;
+import static com.mongodb.client.model.Aggregates.group;
+import static com.mongodb.client.model.Aggregates.lookup;
+import static com.mongodb.client.model.Aggregates.project;
+import static com.mongodb.client.model.Aggregates.unwind;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.in;
+import static com.mongodb.client.model.Filters.not;
+import static java.lang.String.format;
+import static java.util.stream.Collectors.toList;
+
+@Singleton
+@Slf4j
+public class UserRoleDAOImpl extends BaseDAO implements UserRoleDAO {
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+    private static final String[] DEFAULT_AWS_SHAPES = {"nbShapes_t2.medium_fetching", "compShapes_c4.xlarge_fetching"};
+    private static final String[] DEFAULT_GCP_SHAPES = {"compShapes_n1-standard-2_fetching", "nbShapes_n1-standard-2_fetching"};
+    private static final String[] DEFAULT_AZURE_SHAPES = {"nbShapes_Standard_E4s_v3_fetching", "compShapes_Standard_E4s_v3_fetching"};
+    private static final String ROLES_FILE_FORMAT = "/mongo/%s/mongo_roles.json";
+    private static final String USERS_FIELD = "users";
+    private static final String GROUPS_FIELD = "groups";
+    private static final String DESCRIPTION = "description";
+    private static final String TYPE = "type";
+    private static final String CLOUD = "cloud";
+    private static final String ROLES = "roles";
+    private static final String GROUPS = "$groups";
+    private static final String GROUP = "group";
+    private static final String EXPLORATORY_SHAPES_FIELD = "exploratory_shapes";
+    private static final String PAGES_FIELD = "pages";
+    private static final String EXPLORATORIES_FIELD = "exploratories";
+    private static final String COMPUTATIONALS_FIELD = "computationals";
+    private static final String GROUP_INFO = "groupInfo";
+
+
+    @Override
+    public List<UserRoleDto> findAll() {
+        return find(MongoCollections.ROLES, UserRoleDto.class);
+    }
+
+    @Override
+    public void insert(UserRoleDto dto) {
+        insertOne(MongoCollections.ROLES, dto, dto.getId());
+    }
+
+    @Override
+    public void insert(List<UserRoleDto> roles) {
+        roles.forEach(this::insert);
+    }
+
+    @Override
+    public boolean update(UserRoleDto dto) {
+        final Document userRoleDocument = convertToBson(dto).append(TIMESTAMP, new Date());
+        return conditionMatched(updateOne(MongoCollections.ROLES,
+                eq(ID, dto.getId()),
+                new Document(SET, userRoleDocument)));
+    }
+
+    @Override
+    public void updateMissingRoles(CloudProvider cloudProvider) {
+        getUserRoleFromFile(cloudProvider)
+                .stream()
+                .peek(u -> u.setGroups(Collections.emptySet()))
+                .filter(u -> findAll()
+                        .stream()
+                        .map(UserRoleDto::getId)
+                        .noneMatch(id -> id.equals(u.getId())))
+                .forEach(this::insert);
+
+        addGroupToRole(aggregateRolesByGroup()
+                        .stream()
+                        .map(UserGroupDto::getGroup)
+                        .collect(Collectors.toSet()),
+                getDefaultShapes(cloudProvider));
+    }
+
+    @Override
+    public boolean addGroupToRole(Set<String> groups, Set<String> roleIds) {
+        return conditionMatched(updateMany(MongoCollections.ROLES, in(ID, roleIds), addToSet(GROUPS_FIELD,
+                groups)));
+    }
+
+    @Override
+    public void removeGroupWhenRoleNotIn(String group, Set<String> roleIds) {
+        updateMany(MongoCollections.ROLES, not(in(ID, roleIds)), pull(GROUPS_FIELD, group));
+    }
+
+    @Override
+    public void removeUnnecessaryRoles(CloudProvider cloudProviderToBeRemoved, List<CloudProvider> remainingProviders) {
+        if (remainingProviders.contains(cloudProviderToBeRemoved)) {
+            return;
+        }
+        List<UserRoleDto> remainingRoles = new ArrayList<>();
+        remainingProviders.forEach(p -> remainingRoles.addAll(getUserRoleFromFile(p)));
+
+        getUserRoleFromFile(cloudProviderToBeRemoved)
+                .stream()
+                .filter(role -> UserRoleDto.cloudSpecificTypes().contains(role.getType()))
+                .map(UserRoleDto::getId)
+                .filter(u -> remainingRoles
+                        .stream()
+                        .map(UserRoleDto::getId)
+                        .noneMatch(id -> id.equals(u)))
+                .forEach(this::remove);
+    }
+
+    @Override
+    public void remove(String roleId) {
+        deleteOne(MongoCollections.ROLES, eq(ID, roleId));
+    }
+
+    @Override
+    public boolean removeGroup(String groupId) {
+        return conditionMatched(updateMany(MongoCollections.ROLES, in(GROUPS_FIELD, groupId), pull(GROUPS_FIELD,
+                groupId)));
+    }
+
+    @Override
+    public List<UserGroupDto> aggregateRolesByGroup() {
+        final Document role = roleDocument();
+        final Bson groupBy = group(GROUPS, new BsonField(ROLES, new Document(ADD_TO_SET, role)));
+        final Bson lookup = lookup(USER_GROUPS, ID, ID, GROUP_INFO);
+        final List<Bson> pipeline = Arrays.asList(unwind(GROUPS), groupBy, lookup,
+                project(new Document(GROUP, "$" + ID).append(GROUP_INFO, elementAt(GROUP_INFO, 0))
+                        .append(ROLES, "$" + ROLES)),
+                project(new Document(GROUP, "$" + ID).append(USERS_FIELD, "$" + GROUP_INFO + "." + USERS_FIELD)
+                        .append(ROLES, "$" + ROLES)));
+
+        return stream(aggregate(MongoCollections.ROLES, pipeline))
+                .map(d -> convertFromDocument(d, UserGroupDto.class))
+                .collect(toList());
+    }
+
+    private List<UserRoleDto> getUserRoleFromFile(CloudProvider cloudProvider) {
+        try (InputStream is = getClass().getResourceAsStream(format(ROLES_FILE_FORMAT, cloudProvider.getName()))) {
+            return MAPPER.readValue(is, new TypeReference<List<UserRoleDto>>() {
+            });
+        } catch (IOException e) {
+            log.error("Can not marshall datalab roles due to: {}", e.getMessage(), e);
+            throw new IllegalStateException("Can not marshall datalab roles due to: " + e.getMessage());
+        }
+    }
+
+    private Set<String> getDefaultShapes(CloudProvider cloudProvider) {
+        if (cloudProvider == CloudProvider.AWS) {
+            return Stream.of(DEFAULT_AWS_SHAPES).collect(Collectors.toSet());
+        } else if (cloudProvider == CloudProvider.GCP) {
+            return Stream.of(DEFAULT_GCP_SHAPES).collect(Collectors.toSet());
+        } else if (cloudProvider == CloudProvider.AZURE) {
+            return Stream.of(DEFAULT_AZURE_SHAPES).collect(Collectors.toSet());
+        } else {
+            throw new DatalabException("Unsupported cloud provider " + cloudProvider);
+        }
+    }
+
+    private Document roleDocument() {
+        return new Document().append(ID, "$" + ID)
+                .append(DESCRIPTION, "$" + DESCRIPTION)
+                .append(TYPE, "$" + TYPE)
+                .append(CLOUD, "$" + CLOUD)
+                .append(USERS_FIELD, "$" + USERS_FIELD)
+                .append(EXPLORATORY_SHAPES_FIELD, "$" + EXPLORATORY_SHAPES_FIELD)
+                .append(PAGES_FIELD, "$" + PAGES_FIELD)
+                .append(EXPLORATORIES_FIELD, "$" + EXPLORATORIES_FIELD)
+                .append(COMPUTATIONALS_FIELD, "$" + COMPUTATIONALS_FIELD);
+    }
+
+    private boolean conditionMatched(UpdateResult updateResult) {
+        return updateResult.getMatchedCount() > 0;
+    }
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserSettingsDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserSettingsDAO.java
new file mode 100644
index 0000000..7e06eb3
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserSettingsDAO.java
@@ -0,0 +1,77 @@
+/*
+ * 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.datalab.backendapi.dao;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.UserDTO;
+import io.dropwizard.auth.Auth;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Optional;
+
+import static com.epam.datalab.backendapi.dao.MongoCollections.USER_SETTINGS;
+import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Updates.set;
+
+/**
+ * DAO for the user preferences.
+ */
+public class UserSettingsDAO extends BaseDAO {
+    private static final String USER_UI_SETTINGS_FIELD = "userUISettings";
+    private static final String USER_ALLOWED_BUDGET = "allowedBudget";
+
+    /**
+     * Returns the user preferences of UI dashboard.
+     *
+     * @param userInfo user info.
+     * @return JSON content.
+     */
+    public String getUISettings(@Auth UserInfo userInfo) {
+        return findOne(USER_SETTINGS, eq(ID, userInfo.getName()))
+                .map(d -> d.getString(USER_UI_SETTINGS_FIELD))
+                .orElse(StringUtils.EMPTY);
+    }
+
+    /**
+     * Store the user preferences of UI dashboard.
+     *
+     * @param userInfo user info.
+     * @param settings user preferences in JSON format.
+     */
+    public void setUISettings(UserInfo userInfo, String settings) {
+        updateOne(USER_SETTINGS,
+                eq(ID, userInfo.getName()),
+                set(USER_UI_SETTINGS_FIELD, settings),
+                true);
+    }
+
+    public void updateBudget(UserDTO allowedBudgetDTO) {
+        updateOne(USER_SETTINGS,
+                eq(ID, allowedBudgetDTO.getName()),
+                set(USER_ALLOWED_BUDGET, allowedBudgetDTO.getBudget()),
+                true);
+    }
+
+    public Optional<Integer> getAllowedBudget(String user) {
+        return findOne(USER_SETTINGS, eq(ID, user))
+                .flatMap(d -> Optional.ofNullable(d.getInteger(USER_ALLOWED_BUDGET)));
+    }
+
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditActionEnum.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditActionEnum.java
new file mode 100644
index 0000000..ed18240
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/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.datalab.backendapi.domain;
+
+public enum AuditActionEnum {
+    CREATE, SET_UP_SCHEDULER, START, STOP, TERMINATE, RECONFIGURE, UPDATE, CONNECT, DISCONNECT, UPLOAD, DOWNLOAD, DELETE, INSTALL_LIBS, FOLLOW_LINK, LOG_IN
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditCreateDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditCreateDTO.java
new file mode 100644
index 0000000..0fb37d3
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditCreateDTO.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
+
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class AuditCreateDTO {
+    @NotBlank(message = "field cannot be empty")
+    @JsonProperty("resource_name")
+    private final String resourceName;
+    @NotBlank(message = "field cannot be empty")
+    private final String info;
+    private final AuditResourceTypeEnum type;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditDTO.java
new file mode 100644
index 0000000..353f6b2
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditDTO.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.datalab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@Builder
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class AuditDTO {
+    private final String user;
+    private final AuditActionEnum action;
+    private final AuditResourceTypeEnum type;
+    private final String project;
+    private final String resourceName;
+    private final String info;
+    private Date timestamp;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditPaginationDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditPaginationDTO.java
new file mode 100644
index 0000000..194d70a
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditPaginationDTO.java
@@ -0,0 +1,43 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+import java.util.Set;
+
+@Data
+@Builder
+public class AuditPaginationDTO {
+    @JsonProperty("page_count")
+    private final int totalPageCount;
+    private final List<AuditDTO> audit;
+    @JsonProperty("user_filter")
+    private final Set<String> userFilter;
+    @JsonProperty("project_filter")
+    private final Set<String> projectFilter;
+    @JsonProperty("resource_name_filter")
+    private final Set<String> resourceNameFilter;
+    @JsonProperty("resource_type_filter")
+    private final Set<String> resourceTypeFilter;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditResourceTypeEnum.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditResourceTypeEnum.java
new file mode 100644
index 0000000..1ca0fdf
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditResourceTypeEnum.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.datalab.backendapi.domain;
+
+public enum AuditResourceTypeEnum {
+    PROJECT, EDGE_NODE, NOTEBOOK, COMPUTE, BUCKET, ENDPOINT, GROUP, IMAGE, GIT_ACCOUNT, LOG_IN, WEB_TERMINAL
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AutoCompleteEnum.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AutoCompleteEnum.java
new file mode 100644
index 0000000..6869623
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AutoCompleteEnum.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.datalab.backendapi.domain;
+
+public enum AutoCompleteEnum {
+    NONE, UPDATING, ENABLED
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/BillingReport.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/BillingReport.java
new file mode 100644
index 0000000..2d550df
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/BillingReport.java
@@ -0,0 +1,45 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Data
+@Builder
+public class BillingReport {
+    private String sbn;
+    private String name;
+    @JsonProperty("report_lines")
+    private List<BillingReportLine> reportLines;
+    @JsonProperty("from")
+    private LocalDate usageDateFrom;
+    @JsonProperty("to")
+    private LocalDate usageDateTo;
+    @JsonProperty("total_cost")
+    private double totalCost;
+    private String currency;
+    @JsonProperty("is_full")
+    private boolean isReportHeaderCompletable;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/BillingReportLine.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/BillingReportLine.java
new file mode 100644
index 0000000..8268652
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/BillingReportLine.java
@@ -0,0 +1,56 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.billing.BillingResourceType;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+
+import java.time.LocalDate;
+
+@Data
+@Builder
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BillingReportLine {
+    private String datalabId;
+    private String application;
+    @JsonProperty("resource_name")
+    private String resourceName;
+    private String project;
+    private String endpoint;
+    private String user;
+    @JsonProperty("from")
+    private LocalDate usageDateFrom;
+    @JsonProperty("to")
+    private LocalDate usageDateTo;
+    private String usageDate;
+    private String product;
+    private String usageType;
+    private Double cost;
+    private String currency;
+    @JsonProperty("resource_type")
+    private BillingResourceType resourceType;
+    private UserInstanceStatus status;
+    private String shape;
+    private String exploratoryName;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/BudgetDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/BudgetDTO.java
new file mode 100644
index 0000000..b2eb6cc
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/BudgetDTO.java
@@ -0,0 +1,36 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class BudgetDTO {
+    private Integer value;
+    private boolean monthlyBudget;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/CreateProjectDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/CreateProjectDTO.java
new file mode 100644
index 0000000..6920d9d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/CreateProjectDTO.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.util.Set;
+
+@Data
+public class CreateProjectDTO {
+    @NotNull
+    private final String name;
+    @NotNull
+    private final Set<String> groups;
+    @NotNull
+    final Set<String> endpoints;
+    @NotNull
+    @Pattern(regexp = "^ssh-.*\\n?", message = "format is incorrect. Please use the openSSH format")
+    private final String key;
+    @NotNull
+    private final String tag;
+    @JsonProperty("shared_image_enabled")
+    private boolean sharedImageEnabled;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/EndpointDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/EndpointDTO.java
new file mode 100644
index 0000000..168a1e6
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/EndpointDTO.java
@@ -0,0 +1,50 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.epam.datalab.cloud.CloudProvider;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
+import org.hibernate.validator.constraints.URL;
+
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class EndpointDTO {
+
+    private static final String URL_REGEXP_VALIDATION = "^(http(s)?)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
+    @NotBlank(message = "field cannot be empty")
+    private final String name;
+    @URL(regexp = URL_REGEXP_VALIDATION, message = "field is in improper format!")
+    private final String url;
+    @NotBlank(message = "field cannot be empty")
+    private final String account;
+    @JsonProperty("endpoint_tag")
+    private final String tag;
+    private final EndpointStatus status;
+    private final CloudProvider cloudProvider;
+
+    public enum EndpointStatus {
+        ACTIVE,
+        INACTIVE
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/EndpointResourcesDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/EndpointResourcesDTO.java
new file mode 100644
index 0000000..b991d79
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/EndpointResourcesDTO.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.datalab.backendapi.domain;
+
+import com.epam.datalab.dto.UserInstanceDTO;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+public class EndpointResourcesDTO {
+    private List<UserInstanceDTO> exploratories;
+    private List<ProjectDTO> projects;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/ExploratoryLibCache.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/ExploratoryLibCache.java
new file mode 100644
index 0000000..de4d3fa
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/ExploratoryLibCache.java
@@ -0,0 +1,240 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.LibraryAutoCompleteDTO;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.LibListComputationalDTO;
+import com.epam.datalab.dto.LibListExploratoryDTO;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.ComputationalAPI;
+import com.epam.datalab.rest.contracts.ExploratoryAPI;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import io.dropwizard.lifecycle.Managed;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Cache of libraries for exploratory.
+ */
+@Singleton
+public class ExploratoryLibCache implements Managed, Runnable {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ExploratoryLibCache.class);
+
+    @Inject
+    @Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
+    private RESTService provisioningService;
+    @Inject
+    private RequestBuilder requestBuilder;
+    @Inject
+    private RequestId requestId;
+    @Inject
+    private EndpointService endpointService;
+
+    /**
+     * Instance of cache.
+     */
+    private static ExploratoryLibCache libCache;
+
+    /**
+     * Thread of the cache.
+     */
+    private Thread thread;
+
+    /**
+     * List of libraries.
+     */
+    private Map<String, ExploratoryLibList> cache = new HashMap<>();
+
+    /**
+     * Return the list of libraries.
+     */
+    public static ExploratoryLibCache getCache() {
+        synchronized (libCache) {
+            if (libCache.thread == null) {
+                LOGGER.debug("Library cache thread not running and will be started ...");
+                libCache.thread = new Thread(libCache, libCache.getClass().getSimpleName());
+                libCache.thread.start();
+            }
+        }
+        return libCache;
+    }
+
+    @Override
+    public void start() {
+        if (libCache == null) {
+            libCache = this;
+        }
+    }
+
+    @Override
+    public void stop() {
+        if (libCache != null) {
+            synchronized (libCache) {
+                if (libCache.thread != null) {
+                    LOGGER.debug("Library cache thread will be stopped ...");
+                    libCache.thread.interrupt();
+                    libCache.thread = null;
+                    LOGGER.debug("Library cache thread has been stopped");
+                }
+                libCache.cache.clear();
+            }
+        }
+    }
+
+    /**
+     * Return the list of libraries for docker image and group start with prefix from cache.
+     *
+     * @param userInfo  the user info.
+     * @param group     the name of group.
+     * @param startWith the prefix for library name.
+     * @return LibraryAutoCompleteDTO dto
+     */
+    public LibraryAutoCompleteDTO getLibList(UserInfo userInfo, UserInstanceDTO userInstance, String group, String startWith) {
+        ExploratoryLibList libs = getLibs(userInfo, userInstance, group);
+        return libs.getLibs(group, startWith);
+    }
+
+    /**
+     * Return the list of libraries for docker image from cache.
+     *
+     * @param userInfo     the user info.
+     * @param userInstance userInstance
+     * @param cacheKey     the group of library
+     */
+    private ExploratoryLibList getLibs(UserInfo userInfo, UserInstanceDTO userInstance, String cacheKey) {
+        ExploratoryLibList libs;
+        synchronized (cache) {
+            cache.computeIfAbsent(cacheKey, libraries -> new ExploratoryLibList(cacheKey, null));
+            libs = cache.get(cacheKey);
+            if (libs.isUpdateNeeded() && !libs.isUpdating()) {
+                libs.setUpdating();
+                libs.setExpiredTime();
+                requestLibList(userInfo, userInstance, cacheKey);
+            }
+        }
+
+        return libs;
+    }
+
+    /**
+     * Update the list of libraries for docker image in cache.
+     *
+     * @param group   the name of image.
+     * @param content the content of libraries list.
+     */
+    public void updateLibList(String group, String content) {
+        synchronized (cache) {
+            cache.remove(group);
+            cache.put(group, new ExploratoryLibList(group, content));
+        }
+    }
+
+    /**
+     * Set updating library list to false
+     *
+     * @param groupName group name
+     */
+    public void updateLibListStatus(String groupName) {
+        synchronized (cache) {
+            ExploratoryLibList exploratoryLibList = cache.get(groupName);
+            exploratoryLibList.setNotUpdating();
+        }
+    }
+
+    /**
+     * Send request to provisioning service for the list of libraries.
+     *
+     * @param userInfo     the user info.
+     * @param userInstance the notebook info.
+     * @param group        the library group
+     */
+    private void requestLibList(UserInfo userInfo, UserInstanceDTO userInstance, String group) {
+        try {
+
+            LOGGER.info("Ask docker for the list of libraries for user {} and exploratory {} computational {}",
+                    userInfo.getName(), userInstance.getExploratoryId(),
+                    userInstance.getResources());
+
+            String uuid;
+            if (userInstance.getResources() != null && !userInstance.getResources().isEmpty()) {
+                UserComputationalResource userComputationalResource = userInstance.getResources().get(0);
+                EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
+                LibListComputationalDTO dto = requestBuilder.newLibComputationalList(userInfo, userInstance,
+                        userComputationalResource, endpointDTO, group);
+
+                uuid = provisioningService.post(endpointDTO.getUrl() + ComputationalAPI.COMPUTATIONAL_LIB_LIST,
+                        userInfo.getAccessToken(),
+                        dto, String.class);
+            } else {
+                EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
+                LibListExploratoryDTO dto = requestBuilder.newLibExploratoryList(userInfo, userInstance, endpointDTO, group);
+                uuid = provisioningService.post(endpointDTO.getUrl() + ExploratoryAPI.EXPLORATORY_LIB_LIST,
+                        userInfo.getAccessToken(), dto,
+                        String.class);
+            }
+
+            requestId.put(userInfo.getName(), uuid);
+
+        } catch (Exception e) {
+            LOGGER.warn("Ask docker for the status of resources for user {} and exploratory {} fails: {}",
+                    userInfo.getName(), userInstance, e.getLocalizedMessage(), e);
+        }
+    }
+
+
+    @Override
+    public void run() {
+        while (true) {
+            try {
+                Thread.sleep(ExploratoryLibList.UPDATE_REQUEST_TIMEOUT_MILLIS);
+
+                synchronized (cache) {
+                    cache.entrySet().removeIf(e -> e.getValue().isExpired());
+                }
+
+                if (cache.size() == 0) {
+                    synchronized (libCache) {
+                        thread = null;
+                        LOGGER.debug("Library cache thread have no data and will be finished");
+                        return;
+                    }
+                }
+            } catch (InterruptedException e) {
+                LOGGER.trace("Library cache thread has been interrupted");
+                Thread.currentThread().interrupt();
+                break;
+            } catch (Exception e) {
+                LOGGER.warn("Library cache thread unhandled error: {}", e.getLocalizedMessage(), e);
+            }
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/ExploratoryLibList.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/ExploratoryLibList.java
new file mode 100644
index 0000000..6276a63
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/ExploratoryLibList.java
@@ -0,0 +1,250 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.epam.datalab.backendapi.resources.dto.LibraryAutoCompleteDTO;
+import com.epam.datalab.backendapi.resources.dto.LibraryDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.MoreObjects;
+import io.dropwizard.util.Duration;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+/**
+ * Class to store the info about libraries.
+ */
+@Slf4j
+public class ExploratoryLibList {
+
+    /**
+     * Timeout in milliseconds when the info is out of date.
+     */
+    private static final long EXPIRED_TIMEOUT_MILLIS = Duration.hours(2).toMilliseconds();
+
+    /**
+     * Timeout in milliseconds until the is out of date.
+     */
+    private static final long UPDATE_TIMEOUT_MILLIS = Duration.minutes(30).toMilliseconds();
+
+    /**
+     * Timeout in milliseconds for request to update lib.
+     */
+    protected static final long UPDATE_REQUEST_TIMEOUT_MILLIS = Duration.minutes(15).toMilliseconds();
+
+    /**
+     * Group name.
+     */
+    private String group;
+
+    /**
+     * List of libraries group:libraries:version.
+     */
+    private Map<String, Map<String, String>> libs = new HashMap<>();
+
+    /**
+     * Time in milliseconds when the info is out of date.
+     */
+    private long expiredTimeMillis = 0;
+
+    /**
+     * Last access time in milliseconds to the info.
+     */
+    private long accessTimeMillis = 0;
+
+    /**
+     * Update start time in milliseconds.
+     */
+    private long updateStartTimeMillis = 0;
+
+    /**
+     * Update in progress.
+     */
+    private boolean updating = false;
+
+
+    /**
+     * Instantiate the list of libraries.
+     *
+     * @param group   the name of docker's image.
+     * @param content JSON string.
+     */
+    ExploratoryLibList(String group, String content) {
+        this.group = group;
+        if (content != null) {
+            setLibs(content);
+        }
+    }
+
+    /**
+     * Return the list of all groups.
+     */
+    public List<String> getGroupList() {
+        List<String> list = new ArrayList<>(libs.keySet());
+        Collections.sort(list);
+        return list;
+    }
+
+    /**
+     * Return the name of docker image;
+     */
+    public String getGroup() {
+        return group;
+    }
+
+    /**
+     * Return the full list of libraries for group.
+     *
+     * @param group the name of group.
+     */
+    public Map<String, String> getLibs(String group) {
+        return libs.get(group);
+    }
+
+    /**
+     * Return the full list of libraries for group.
+     *
+     * @param content JSON string.
+     */
+    private void setLibs(String content) {
+        ObjectMapper mapper = new ObjectMapper();
+        try {
+            synchronized (this) {
+                @SuppressWarnings("unchecked")
+                Map<String, Map<String, String>> map = mapper.readValue(content, Map.class);
+                for (Map.Entry<String, Map<String, String>> entry : map.entrySet()) {
+                    Map<String, String> group = entry.getValue();
+                    String groupName = entry.getKey();
+                    libs.remove(groupName);
+                    log.info("Update {} group with lib group {} with {} libraries", this.group, groupName, (group != null) ? group.size() : null);
+                    libs.put(groupName, new TreeMap<>(group));
+                }
+                setExpiredTime();
+                updating = false;
+            }
+        } catch (IOException e) {
+            throw new DatalabException("Cannot deserialize the list of libraries. " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    public void setExpiredTime() {
+        expiredTimeMillis = System.currentTimeMillis() + EXPIRED_TIMEOUT_MILLIS;
+        accessTimeMillis = System.currentTimeMillis();
+    }
+
+    /**
+     * Search and return the list of libraries for name's prefix <b>startWith</b>.
+     *
+     * @param group     the name of group.
+     * @param startWith the prefix for library name.
+     * @return LibraryAutoCompleteDTO dto
+     */
+    public LibraryAutoCompleteDTO getLibs(String group, String startWith) {
+        final String startsWithLower = startWith.toLowerCase();
+        Map<String, String> libMap = getLibs(group);
+        if (libMap == null) {
+            return LibraryAutoCompleteDTO.builder()
+                    .autoComplete(isUpdating() ? AutoCompleteEnum.UPDATING : AutoCompleteEnum.NONE)
+                    .libraries(Collections.emptyList())
+                    .build();
+        }
+        List<LibraryDTO> libraries = libMap.entrySet()
+                .stream()
+                .filter(e -> e.getKey().toLowerCase().startsWith(startsWithLower))
+                .map(e -> new LibraryDTO(e.getKey(), e.getValue()))
+                .collect(Collectors.toList());
+
+        return LibraryAutoCompleteDTO.builder()
+                .autoComplete(AutoCompleteEnum.ENABLED)
+                .libraries(libraries)
+                .build();
+    }
+
+    /**
+     * Set last access time.
+     */
+    private void touch() {
+        accessTimeMillis = System.currentTimeMillis();
+    }
+
+    /**
+     * Return <b>true</b> if the info is out of date.
+     */
+    public boolean isExpired() {
+        touch();
+        return (expiredTimeMillis < System.currentTimeMillis());
+    }
+
+    /**
+     * Return <b>true</b> if the info needs to update.
+     */
+    public boolean isUpdateNeeded() {
+        touch();
+        return (accessTimeMillis > expiredTimeMillis - UPDATE_TIMEOUT_MILLIS);
+    }
+
+    /**
+     * Set updating in progress.
+     */
+    public void setUpdating() {
+        updateStartTimeMillis = System.currentTimeMillis();
+        updating = true;
+    }
+
+    /**
+     * Set updating to false.
+     */
+    public void setNotUpdating() {
+        updating = Boolean.FALSE;
+    }
+
+    /**
+     * Return <b>true</b> if the update in progress.
+     */
+    public boolean isUpdating() {
+        if (updating &&
+                updateStartTimeMillis + UPDATE_REQUEST_TIMEOUT_MILLIS < System.currentTimeMillis()) {
+            updating = false;
+        }
+        return updating;
+    }
+
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("group", group)
+                .add("expiredTimeMillis", expiredTimeMillis)
+                .add("accessTimeMillis", accessTimeMillis)
+                .add("updateStartTimeMillis", updateStartTimeMillis)
+                .add("isUpdating", updating)
+                .add("libs", (libs == null ? "null" : "..."))
+                .toString();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/MavenSearchArtifactResponse.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/MavenSearchArtifactResponse.java
new file mode 100644
index 0000000..3dd6bd1
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/MavenSearchArtifactResponse.java
@@ -0,0 +1,82 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@Getter
+public class MavenSearchArtifactResponse {
+
+    @JsonProperty("response")
+    private Response response;
+
+    public void setResponse(Response response) {
+        this.response = response;
+    }
+
+    public int getArtifactCount() {
+        return response.artifactCount;
+    }
+
+    public List<Response.Artifact> getArtifacts() {
+        return response.artifacts;
+    }
+
+    @JsonIgnoreProperties(ignoreUnknown = true)
+    public static class Response {
+        @JsonProperty("numFound")
+        private int artifactCount;
+        @JsonProperty("docs")
+        private List<Artifact> artifacts;
+
+        public void setArtifacts(List<Artifact> artifacts) {
+            this.artifacts = artifacts;
+        }
+
+        @JsonIgnoreProperties(ignoreUnknown = true)
+        public static class Artifact {
+            private String id;
+            @JsonProperty("v")
+            private String version;
+
+            public String getId() {
+                return id;
+            }
+
+            public void setId(String id) {
+                this.id = id;
+            }
+
+            public String getVersion() {
+                return version;
+            }
+
+            public void setVersion(String version) {
+                this.version = version;
+            }
+        }
+    }
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/NotebookTemplate.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/NotebookTemplate.java
new file mode 100644
index 0000000..618de65
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/NotebookTemplate.java
@@ -0,0 +1,40 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+public enum NotebookTemplate {
+    JUPYTER("Jupyter notebook 6.0.2"),
+    JUPYTER_LAB("JupyterLab 0.35.6"),
+    ZEPPELIN("Apache Zeppelin 0.8.2"),
+    DEEP_LEARNING("Deep Learning  2.4"),
+    TENSOR("Jupyter with TensorFlow 2.1.0"),
+    TENSOR_RSTUDIO("RStudio with TensorFlow 2.1.0"),
+    RSTUDIO("RStudio 1.2.5033");
+
+    private String name;
+
+    NotebookTemplate(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/ProjectDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/ProjectDTO.java
new file mode 100644
index 0000000..32bd695
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/ProjectDTO.java
@@ -0,0 +1,104 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.util.List;
+import java.util.Set;
+
+@Data
+@Builder
+@AllArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ProjectDTO {
+    @NotNull
+    private final String name;
+    @NotNull
+    private final Set<String> groups;
+    @NotNull
+    @Pattern(regexp = "^ssh-.*\\n", message = "format is incorrect. Please use the openSSH format")
+    private final String key;
+    @NotNull
+    private final String tag;
+    private final BudgetDTO budget;
+    private final List<ProjectEndpointDTO> endpoints;
+    private final boolean sharedImageEnabled;
+
+
+    public enum Status {
+        CREATING,
+        ACTIVE,
+        FAILED,
+        DELETED,
+        DELETING,
+        DEACTIVATING,
+        ACTIVATING,
+        NOT_ACTIVE;
+
+        public static Status from(UserInstanceStatus userInstanceStatus) {
+            if (userInstanceStatus == UserInstanceStatus.RUNNING) {
+                return ACTIVE;
+            } else if (userInstanceStatus == UserInstanceStatus.TERMINATED) {
+                return DELETED;
+            } else if (userInstanceStatus == UserInstanceStatus.TERMINATING) {
+                return DELETING;
+            } else if (userInstanceStatus == UserInstanceStatus.STOPPING) {
+                return DEACTIVATING;
+            } else if (userInstanceStatus == UserInstanceStatus.STOPPED) {
+                return NOT_ACTIVE;
+            } else if (userInstanceStatus == UserInstanceStatus.STARTING) {
+                return ACTIVATING;
+            } else if (userInstanceStatus == UserInstanceStatus.CREATING) {
+                return CREATING;
+            } else if (userInstanceStatus == UserInstanceStatus.FAILED) {
+                return FAILED;
+            }
+            return Status.valueOf(userInstanceStatus.name());
+        }
+
+        public static UserInstanceStatus from(Status status) {
+            if (status == ACTIVE) {
+                return UserInstanceStatus.RUNNING;
+            } else if (status == ACTIVATING) {
+                return UserInstanceStatus.STARTING;
+            } else if (status == DEACTIVATING) {
+                return UserInstanceStatus.STOPPING;
+            } else if (status == NOT_ACTIVE) {
+                return UserInstanceStatus.STOPPED;
+            } else if (status == DELETING) {
+                return UserInstanceStatus.TERMINATING;
+            } else if (status == DELETED) {
+                return UserInstanceStatus.TERMINATED;
+            } else if (status == CREATING) {
+                return UserInstanceStatus.CREATING;
+            } else if (status == FAILED) {
+                return UserInstanceStatus.FAILED;
+            }
+            throw new IllegalArgumentException();
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/ProjectEndpointDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/ProjectEndpointDTO.java
new file mode 100644
index 0000000..94b9d28
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/ProjectEndpointDTO.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.datalab.backendapi.domain;
+
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import lombok.Data;
+
+@Data
+public class ProjectEndpointDTO {
+    private final String name;
+    private final UserInstanceStatus status;
+    private final EdgeInfo edgeInfo;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/RequestId.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/RequestId.java
new file mode 100644
index 0000000..f81f1e0
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/RequestId.java
@@ -0,0 +1,95 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.epam.datalab.backendapi.dao.RequestIdDAO;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import io.dropwizard.util.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+import java.util.UUID;
+
+/**
+ * Stores and checks the id of requests for Provisioning Service.
+ */
+@Singleton
+public class RequestId {
+    private static final Logger LOGGER = LoggerFactory.getLogger(RequestId.class);
+
+    /**
+     * Timeout in milliseconds when the request id is out of date.
+     */
+    private static final long EXPIRED_TIMEOUT_MILLIS = Duration.hours(12).toMilliseconds();
+
+    @Inject
+    private RequestIdDAO dao;
+
+    /**
+     * Add the request id for user.
+     *
+     * @param username the name of user.
+     * @param uuid     UUID.
+     */
+    public String put(String username, String uuid) {
+        LOGGER.trace("Register request id {} for user {}", uuid, username);
+        dao.put(new RequestIdDTO()
+                .withId(uuid)
+                .withUser(username)
+                .withRequestTime(new Date())
+                .withExpirationTime(new Date(System.currentTimeMillis() + EXPIRED_TIMEOUT_MILLIS)));
+        return uuid;
+    }
+
+    /**
+     * Generate, add and return new UUID.
+     *
+     * @param username the name of user.
+     * @return new UUID
+     */
+    public String get(String username) {
+        return put(UUID.randomUUID().toString(), username);
+    }
+
+    /**
+     * Remove UUID if it exist.
+     *
+     * @param uuid UUID.
+     */
+    public void remove(String uuid) {
+        LOGGER.trace("Unregister request id {}", uuid);
+        dao.delete(uuid);
+    }
+
+    /**
+     * Check and remove UUID, if it not exists throw exception.
+     *
+     * @param uuid UUID.
+     * @return username
+     */
+    public String checkAndRemove(String uuid) {
+        String username = dao.get(uuid).getUser();
+        LOGGER.trace("Unregister request id {} for user {}", uuid, username);
+        dao.delete(uuid);
+        return username;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/RequestIdDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/RequestIdDTO.java
new file mode 100644
index 0000000..a96ad6a
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/RequestIdDTO.java
@@ -0,0 +1,146 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import java.util.Date;
+
+/**
+ * Store request id info.
+ *
+ * @author Usein_Faradzhev
+ */
+public class RequestIdDTO {
+    @JsonProperty("_id")
+    private String id;
+
+    @JsonProperty
+    private String user;
+
+    @JsonProperty
+    private Date requestTime;
+
+    @JsonProperty
+    private Date expirationTime;
+
+    /**
+     * Return request id.
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Set request id.
+     */
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    /**
+     * Set request id.
+     */
+    public RequestIdDTO withId(String id) {
+        setId(id);
+        return this;
+    }
+
+    /**
+     * Return user name.
+     */
+    public String getUser() {
+        return user;
+    }
+
+    /**
+     * Set user name.
+     */
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    /**
+     * Set user name.
+     */
+    public RequestIdDTO withUser(String user) {
+        setUser(user);
+        return this;
+    }
+
+    /**
+     * Return request time.
+     */
+    public Date getRequestTime() {
+        return requestTime;
+    }
+
+    /**
+     * Set request time.
+     */
+    public void setRequestTime(Date requestTime) {
+        this.requestTime = requestTime;
+    }
+
+    /**
+     * Set request time.
+     */
+    public RequestIdDTO withRequestTime(Date requestTime) {
+        setRequestTime(requestTime);
+        return this;
+    }
+
+    /**
+     * Return expiration time.
+     */
+    public Date getExpirationTime() {
+        return expirationTime;
+    }
+
+    /**
+     * Set expiration time.
+     */
+    public void setExpirationTime(Date expirationTime) {
+        this.expirationTime = expirationTime;
+    }
+
+    /**
+     * Set expiration time.
+     */
+    public RequestIdDTO withExpirationTime(Date expirationTime) {
+        setExpirationTime(expirationTime);
+        return this;
+    }
+
+    public ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("id", id)
+                .add("user", user)
+                .add("requestTime", requestTime)
+                .add("expirationTime", expirationTime);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/SchedulerConfigurationData.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/SchedulerConfigurationData.java
new file mode 100644
index 0000000..5199e69
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/SchedulerConfigurationData.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.datalab.backendapi.domain;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class SchedulerConfigurationData {
+    private final boolean enabled;
+    @NotNull
+    private final String cron;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/UpdateProjectBudgetDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/UpdateProjectBudgetDTO.java
new file mode 100644
index 0000000..c8efe76
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/UpdateProjectBudgetDTO.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UpdateProjectBudgetDTO {
+    @NotNull
+    private final String project;
+    @NotNull
+    private final Integer budget;
+    private final boolean monthlyBudget;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/UpdateProjectDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/UpdateProjectDTO.java
new file mode 100644
index 0000000..5e16c4d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/UpdateProjectDTO.java
@@ -0,0 +1,40 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.Set;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UpdateProjectDTO {
+    @NotNull
+    private final String name;
+    @NotNull
+    private final Set<String> endpoints;
+    @NotNull
+    private final Set<String> groups;
+    @JsonProperty("shared_image_enabled")
+    private final boolean sharedImageEnabled;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dropwizard/bundles/DatalabKeycloakBundle.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dropwizard/bundles/DatalabKeycloakBundle.java
new file mode 100644
index 0000000..8b1a182
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dropwizard/bundles/DatalabKeycloakBundle.java
@@ -0,0 +1,58 @@
+/*
+ * 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.datalab.backendapi.dropwizard.bundles;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.auth.KeycloakAuthenticator;
+import com.epam.datalab.backendapi.auth.SelfServiceSecurityAuthorizer;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.google.inject.Inject;
+import de.ahus1.keycloak.dropwizard.KeycloakBundle;
+import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.Authorizer;
+
+import java.security.Principal;
+
+public class DatalabKeycloakBundle extends KeycloakBundle<SelfServiceApplicationConfiguration> {
+
+    @Inject
+    private KeycloakAuthenticator authenticator;
+
+    @Override
+    protected KeycloakConfiguration getKeycloakConfiguration(SelfServiceApplicationConfiguration configuration) {
+        return configuration.getKeycloakConfiguration();
+    }
+
+    @Override
+    protected Class<? extends Principal> getUserClass() {
+        return UserInfo.class;
+    }
+
+    @Override
+    protected Authorizer createAuthorizer() {
+        return new SelfServiceSecurityAuthorizer();
+    }
+
+    @Override
+    protected Authenticator createAuthenticator(KeycloakConfiguration configuration) {
+        return new KeycloakAuthenticator(configuration);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dropwizard/listeners/MongoStartupListener.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dropwizard/listeners/MongoStartupListener.java
new file mode 100644
index 0000000..f4e045c
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dropwizard/listeners/MongoStartupListener.java
@@ -0,0 +1,97 @@
+/*
+ * 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.datalab.backendapi.dropwizard.listeners;
+
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.EndpointDAO;
+import com.epam.datalab.backendapi.dao.SettingsDAO;
+import com.epam.datalab.backendapi.dao.UserRoleDAO;
+import com.epam.datalab.backendapi.resources.dto.UserRoleDto;
+import com.epam.datalab.cloud.CloudProvider;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import io.dropwizard.lifecycle.ServerLifecycleListener;
+import lombok.extern.slf4j.Slf4j;
+import org.eclipse.jetty.server.Server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import static java.lang.String.format;
+import static java.util.Comparator.comparing;
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.toCollection;
+
+
+@Slf4j
+public class MongoStartupListener implements ServerLifecycleListener {
+
+    private static final String ROLES_FILE_FORMAT = "/mongo/%s/mongo_roles.json";
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+    private final UserRoleDAO userRoleDao;
+    private final SelfServiceApplicationConfiguration configuration;
+    private final SettingsDAO settingsDAO;
+    private final EndpointDAO endpointDAO;
+
+    @Inject
+    public MongoStartupListener(UserRoleDAO userRoleDao, SelfServiceApplicationConfiguration configuration,
+                                SettingsDAO settingsDAO, EndpointDAO endpointDAO) {
+        this.userRoleDao = userRoleDao;
+        this.configuration = configuration;
+        this.settingsDAO = settingsDAO;
+        this.endpointDAO = endpointDAO;
+    }
+
+    @Override
+    public void serverStarted(Server server) {
+        settingsDAO.setServiceBaseName(configuration.getServiceBaseName());
+        settingsDAO.setConfOsFamily(configuration.getOs());
+        settingsDAO.setSsnInstanceSize(configuration.getSsnInstanceSize());
+        if (userRoleDao.findAll().isEmpty()) {
+            log.debug("Populating DataLab roles into database");
+            userRoleDao.insert(getRoles());
+        } else {
+            log.info("Roles already populated. Do nothing ...");
+        }
+    }
+
+    private List<UserRoleDto> getRoles() {
+        Set<UserRoleDto> userRoles = new HashSet<>();
+        endpointDAO.getEndpoints().forEach(e -> userRoles.addAll(getUserRoleFromFile(e.getCloudProvider())));
+        return userRoles.stream().collect(collectingAndThen(toCollection(() -> new TreeSet<>(comparing(UserRoleDto::getId))),
+                ArrayList::new));
+    }
+
+    private List<UserRoleDto> getUserRoleFromFile(CloudProvider cloudProvider) {
+        try (InputStream is = getClass().getResourceAsStream(format(ROLES_FILE_FORMAT, cloudProvider.getName()))) {
+            return MAPPER.readValue(is, new TypeReference<List<UserRoleDto>>() {
+            });
+        } catch (IOException e) {
+            log.error("Can not marshall datalab roles due to: {}", e.getMessage(), e);
+            throw new IllegalStateException("Can not marshall datalab roles due to: " + e.getMessage());
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dropwizard/listeners/RestoreHandlerStartupListener.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dropwizard/listeners/RestoreHandlerStartupListener.java
new file mode 100644
index 0000000..b7c9cef
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dropwizard/listeners/RestoreHandlerStartupListener.java
@@ -0,0 +1,50 @@
+/*
+ * 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.datalab.backendapi.dropwizard.listeners;
+
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.rest.client.RESTService;
+import io.dropwizard.lifecycle.ServerLifecycleListener;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jetty.server.Server;
+
+@Slf4j
+public class RestoreHandlerStartupListener implements ServerLifecycleListener {
+
+    private final RESTService provisioningService;
+    private final EndpointService endpointService;
+
+    public RestoreHandlerStartupListener(RESTService provisioningService, EndpointService endpointService) {
+        this.provisioningService = provisioningService;
+        this.endpointService = endpointService;
+    }
+
+    @Override
+    public void serverStarted(Server server) {
+        try {
+            endpointService.getEndpointsWithStatus(EndpointDTO.EndpointStatus.ACTIVE)
+                    .forEach(e -> provisioningService.post(e.getUrl() + "/handler/restore", StringUtils.EMPTY, Object.class));
+        } catch (Exception e) {
+            log.error("Exception occurred during restore handler request: {}", e.getMessage(), e);
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/healthcheck/MongoHealthCheck.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/healthcheck/MongoHealthCheck.java
new file mode 100644
index 0000000..20c049b
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/healthcheck/MongoHealthCheck.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.backendapi.healthcheck;
+
+import com.codahale.metrics.health.HealthCheck;
+import com.epam.datalab.mongo.MongoService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class MongoHealthCheck extends HealthCheck {
+    private final MongoService mongoService;
+
+    @Inject
+    public MongoHealthCheck(MongoService mongoService) {
+        this.mongoService = mongoService;
+    }
+
+    @Override
+    protected Result check() {
+        try {
+            mongoService.ping();
+        } catch (Exception e) {
+            log.error("Mongo is unavailable {}", e.getMessage(), e);
+            return Result.unhealthy(e.getMessage());
+        }
+        return Result.healthy();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/interceptor/AuditInterceptor.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/interceptor/AuditInterceptor.java
new file mode 100644
index 0000000..94a7068
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/interceptor/AuditInterceptor.java
@@ -0,0 +1,127 @@
+/*
+ * 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.datalab.backendapi.interceptor;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Audit;
+import com.epam.datalab.backendapi.annotation.Info;
+import com.epam.datalab.backendapi.annotation.Project;
+import com.epam.datalab.backendapi.annotation.ResourceName;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.domain.AuditActionEnum;
+import com.epam.datalab.backendapi.domain.AuditDTO;
+import com.epam.datalab.backendapi.domain.AuditResourceTypeEnum;
+import com.epam.datalab.backendapi.service.AuditService;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.lang3.StringUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Objects;
+import java.util.stream.IntStream;
+
+@Slf4j
+public class AuditInterceptor implements MethodInterceptor {
+    @Inject
+    private AuditService auditService;
+    @Inject
+    private SelfServiceApplicationConfiguration configuration;
+
+    @Override
+    public Object invoke(MethodInvocation mi) throws Throwable {
+        if (configuration.isAuditEnabled()) {
+            Method method = mi.getMethod();
+            final Parameter[] parameters = mi.getMethod().getParameters();
+            final String user = getUserInfo(mi, parameters);
+            final AuditActionEnum action = getAuditAction(method);
+            final AuditResourceTypeEnum resourceType = getResourceType(method);
+            final String project = getProject(mi, parameters);
+            final String resourceName = getResourceName(mi, parameters);
+            final String auditInfo = getInfo(mi, parameters);
+
+            AuditDTO auditCreateDTO = AuditDTO.builder()
+                    .user(user)
+                    .action(action)
+                    .type(resourceType)
+                    .project(project)
+                    .resourceName(resourceName)
+                    .info(auditInfo)
+                    .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 DatalabException("UserInfo parameter wanted!"));
+    }
+
+    private AuditActionEnum getAuditAction(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 DatalabException("'Audit' annotation wanted!"));
+    }
+
+    private AuditResourceTypeEnum getResourceType(Method method) {
+        Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
+        return IntStream.range(0, method.getDeclaredAnnotations().length)
+                .filter(i -> declaredAnnotations[i] instanceof Audit)
+                .mapToObj(i -> ((Audit) declaredAnnotations[i]).type())
+                .findAny()
+                .orElseThrow(() -> new DatalabException("'Audit' annotation wanted!"));
+    }
+
+    private String getProject(MethodInvocation mi, Parameter[] parameters) {
+        return IntStream.range(0, parameters.length)
+                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(Project.class)))
+                .mapToObj(i -> (String) mi.getArguments()[i])
+                .findAny()
+                .orElse(StringUtils.EMPTY);
+    }
+
+    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()
+                .orElse(StringUtils.EMPTY);
+    }
+
+    private String getInfo(MethodInvocation mi, Parameter[] parameters) {
+        return IntStream.range(0, parameters.length)
+                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(Info.class)) && Objects.nonNull(mi.getArguments()[i]))
+                .mapToObj(i -> (String) mi.getArguments()[i])
+                .findAny()
+                .orElse(StringUtils.EMPTY);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/interceptor/BudgetLimitInterceptor.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/interceptor/BudgetLimitInterceptor.java
new file mode 100644
index 0000000..421d37d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/interceptor/BudgetLimitInterceptor.java
@@ -0,0 +1,64 @@
+/*
+ * 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.datalab.backendapi.interceptor;
+
+import com.epam.datalab.backendapi.annotation.Project;
+import com.epam.datalab.backendapi.dao.BillingDAO;
+import com.epam.datalab.backendapi.service.BillingService;
+import com.epam.datalab.exceptions.ResourceQuoteReachedException;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Objects;
+import java.util.stream.IntStream;
+
+@Slf4j
+public class BudgetLimitInterceptor implements MethodInterceptor {
+    @Inject
+    private BillingDAO billingDAO;
+    @Inject
+    private BillingService billingService;
+
+    @Override
+    public Object invoke(MethodInvocation mi) throws Throwable {
+        if (projectQuoteReached(mi) || billingDAO.isBillingQuoteReached()) {
+            final Method method = mi.getMethod();
+            log.warn("Execution of method {} failed because of reaching resource limit quote", method.getName());
+            throw new ResourceQuoteReachedException("Operation can not be finished. Resource quote is reached");
+        } else {
+            return mi.proceed();
+        }
+    }
+
+    private Boolean projectQuoteReached(MethodInvocation mi) {
+
+        final Parameter[] parameters = mi.getMethod().getParameters();
+        return IntStream.range(0, parameters.length)
+                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(Project.class)))
+                .mapToObj(i -> (String) mi.getArguments()[i])
+                .findAny()
+                .map(billingService::isProjectQuoteReached)
+                .orElse(Boolean.FALSE);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/interceptor/ProjectAdminInterceptor.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/interceptor/ProjectAdminInterceptor.java
new file mode 100644
index 0000000..f978153
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/interceptor/ProjectAdminInterceptor.java
@@ -0,0 +1,74 @@
+/*
+ * 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.datalab.backendapi.interceptor;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Project;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.roles.UserRoles;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceQuoteReachedException;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Objects;
+import java.util.stream.IntStream;
+
+@Slf4j
+public class ProjectAdminInterceptor implements MethodInterceptor {
+    @Inject
+    private ProjectService projectService;
+
+    @Override
+    public Object invoke(MethodInvocation mi) throws Throwable {
+        if (grantAccess(mi)) {
+            return mi.proceed();
+        } else {
+            final Method method = mi.getMethod();
+            log.warn("Execution of method {} failed because user doesn't have appropriate permission", method.getName());
+            throw new ResourceQuoteReachedException("Operation can not be finished. User doesn't have appropriate permission");
+        }
+    }
+
+    private boolean grantAccess(MethodInvocation mi) {
+        final Parameter[] parameters = mi.getMethod().getParameters();
+        String project = IntStream.range(0, parameters.length)
+                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(Project.class)))
+                .mapToObj(i -> (String) mi.getArguments()[i])
+                .findAny()
+                .orElseThrow(() -> new DatalabException("Project parameter wanted!"));
+        UserInfo userInfo = IntStream.range(0, parameters.length)
+                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(User.class)))
+                .mapToObj(i -> (UserInfo) mi.getArguments()[i])
+                .findAny()
+                .orElseThrow(() -> new DatalabException("UserInfo parameter wanted!"));
+
+        return checkPermission(userInfo, project);
+    }
+
+    private boolean checkPermission(UserInfo userInfo, String project) {
+        return UserRoles.isAdmin(userInfo) || UserRoles.isProjectAdmin(userInfo, projectService.get(project).getGroups());
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/CloudProviderModule.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/CloudProviderModule.java
new file mode 100644
index 0000000..bc261ed
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/CloudProviderModule.java
@@ -0,0 +1,112 @@
+/*
+ * 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.datalab.backendapi.modules;
+
+import com.epam.datalab.backendapi.SelfServiceApplication;
+import com.epam.datalab.backendapi.annotation.Audit;
+import com.epam.datalab.backendapi.annotation.BudgetLimited;
+import com.epam.datalab.backendapi.annotation.ProjectAdmin;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.interceptor.AuditInterceptor;
+import com.epam.datalab.backendapi.interceptor.BudgetLimitInterceptor;
+import com.epam.datalab.backendapi.interceptor.ProjectAdminInterceptor;
+import com.epam.datalab.backendapi.resources.BillingResource;
+import com.epam.datalab.backendapi.resources.BucketResource;
+import com.epam.datalab.backendapi.resources.aws.ComputationalResourceAws;
+import com.epam.datalab.backendapi.resources.azure.ComputationalResourceAzure;
+import com.epam.datalab.backendapi.resources.gcp.ComputationalResourceGcp;
+import com.epam.datalab.backendapi.resources.gcp.GcpOauthResource;
+import com.epam.datalab.backendapi.service.BillingService;
+import com.epam.datalab.backendapi.service.InfrastructureInfoService;
+import com.epam.datalab.backendapi.service.InfrastructureTemplateService;
+import com.epam.datalab.backendapi.service.impl.BillingServiceImpl;
+import com.epam.datalab.backendapi.service.impl.InfrastructureInfoServiceImpl;
+import com.epam.datalab.backendapi.service.impl.InfrastructureTemplateServiceImpl;
+import com.epam.datalab.cloud.CloudModule;
+import com.epam.datalab.mongo.MongoServiceFactory;
+import com.fiestacabin.dropwizard.quartz.SchedulerConfiguration;
+import com.google.inject.Injector;
+import com.google.inject.Provides;
+import com.google.inject.Singleton;
+import io.dropwizard.setup.Environment;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.impl.StdSchedulerFactory;
+
+import static com.google.inject.matcher.Matchers.annotatedWith;
+import static com.google.inject.matcher.Matchers.any;
+
+public class CloudProviderModule extends CloudModule {
+
+    private static final String MONGO_URI_FORMAT = "mongodb://%s:%s@%s:%d/%s";
+    private static final String QUARTZ_MONGO_URI_PROPERTY = "org.quartz.jobStore.mongoUri";
+    private static final String QUARTZ_DB_NAME = "org.quartz.jobStore.dbName";
+
+    private SelfServiceApplicationConfiguration configuration;
+
+    public CloudProviderModule(SelfServiceApplicationConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    @Override
+    protected void configure() {
+        bind(BillingService.class).to(BillingServiceImpl.class);
+        bind(InfrastructureInfoService.class).to(InfrastructureInfoServiceImpl.class);
+        bind(InfrastructureTemplateService.class).to(InfrastructureTemplateServiceImpl.class);
+        bind(SchedulerConfiguration.class).toInstance(
+                new SchedulerConfiguration(SelfServiceApplication.class.getPackage().getName()));
+
+        final BudgetLimitInterceptor budgetLimitInterceptor = new BudgetLimitInterceptor();
+        requestInjection(budgetLimitInterceptor);
+        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
+    public void init(Environment environment, Injector injector) {
+        environment.jersey().register(injector.getInstance(BillingResource.class));
+        environment.jersey().register(injector.getInstance(ComputationalResourceAws.class));
+        environment.jersey().register(injector.getInstance(ComputationalResourceAzure.class));
+        environment.jersey().register(injector.getInstance(ComputationalResourceGcp.class));
+        environment.jersey().register(injector.getInstance(BucketResource.class));
+        if (injector.getInstance(SelfServiceApplicationConfiguration.class).isGcpOuauth2AuthenticationEnabled()) {
+            environment.jersey().register(injector.getInstance(GcpOauthResource.class));
+        }
+    }
+
+    @Provides
+    @Singleton
+    Scheduler provideScheduler(SelfServiceApplicationConfiguration configuration) throws SchedulerException {
+        final MongoServiceFactory mongoFactory = configuration.getMongoFactory();
+        final String database = mongoFactory.getDatabase();
+        final String mongoUri = String.format(MONGO_URI_FORMAT, mongoFactory.getUsername(), mongoFactory.getPassword(),
+                mongoFactory.getHost(), mongoFactory.getPort(), database);
+        System.setProperty(QUARTZ_MONGO_URI_PROPERTY, mongoUri);
+        System.setProperty(QUARTZ_DB_NAME, database);
+        return StdSchedulerFactory.getDefaultScheduler();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/DevModule.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/DevModule.java
new file mode 100644
index 0000000..9897087
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/DevModule.java
@@ -0,0 +1,197 @@
+/*
+ * 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.datalab.backendapi.modules;
+
+import com.epam.datalab.ModuleBase;
+import com.epam.datalab.auth.contract.SecurityAPI;
+import com.epam.datalab.backendapi.auth.SelfServiceSecurityAuthorizer;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.AuditDAO;
+import com.epam.datalab.backendapi.dao.AuditDAOImpl;
+import com.epam.datalab.backendapi.dao.BackupDAO;
+import com.epam.datalab.backendapi.dao.BackupDAOImpl;
+import com.epam.datalab.backendapi.dao.BaseBillingDAO;
+import com.epam.datalab.backendapi.dao.BillingDAO;
+import com.epam.datalab.backendapi.dao.EndpointDAO;
+import com.epam.datalab.backendapi.dao.EndpointDAOImpl;
+import com.epam.datalab.backendapi.dao.ImageExploratoryDAO;
+import com.epam.datalab.backendapi.dao.ImageExploratoryDAOImpl;
+import com.epam.datalab.backendapi.dao.ProjectDAO;
+import com.epam.datalab.backendapi.dao.ProjectDAOImpl;
+import com.epam.datalab.backendapi.dao.UserGroupDAO;
+import com.epam.datalab.backendapi.dao.UserGroupDAOImpl;
+import com.epam.datalab.backendapi.dao.UserRoleDAO;
+import com.epam.datalab.backendapi.dao.UserRoleDAOImpl;
+import com.epam.datalab.backendapi.service.AccessKeyService;
+import com.epam.datalab.backendapi.service.ApplicationSettingService;
+import com.epam.datalab.backendapi.service.ApplicationSettingServiceImpl;
+import com.epam.datalab.backendapi.service.AuditService;
+import com.epam.datalab.backendapi.service.BackupService;
+import com.epam.datalab.backendapi.service.BucketService;
+import com.epam.datalab.backendapi.service.ComputationalService;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.EnvironmentService;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.ExternalLibraryService;
+import com.epam.datalab.backendapi.service.GitCredentialService;
+import com.epam.datalab.backendapi.service.GuacamoleService;
+import com.epam.datalab.backendapi.service.ImageExploratoryService;
+import com.epam.datalab.backendapi.service.InactivityService;
+import com.epam.datalab.backendapi.service.KeycloakService;
+import com.epam.datalab.backendapi.service.KeycloakServiceImpl;
+import com.epam.datalab.backendapi.service.LibraryService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.service.ReuploadKeyService;
+import com.epam.datalab.backendapi.service.SchedulerJobService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import com.epam.datalab.backendapi.service.SecurityServiceImpl;
+import com.epam.datalab.backendapi.service.SystemInfoService;
+import com.epam.datalab.backendapi.service.TagService;
+import com.epam.datalab.backendapi.service.TagServiceImpl;
+import com.epam.datalab.backendapi.service.UserGroupService;
+import com.epam.datalab.backendapi.service.UserRoleService;
+import com.epam.datalab.backendapi.service.UserRoleServiceImpl;
+import com.epam.datalab.backendapi.service.UserSettingService;
+import com.epam.datalab.backendapi.service.UserSettingServiceImpl;
+import com.epam.datalab.backendapi.service.impl.AccessKeyServiceImpl;
+import com.epam.datalab.backendapi.service.impl.AuditServiceImpl;
+import com.epam.datalab.backendapi.service.impl.BackupServiceImpl;
+import com.epam.datalab.backendapi.service.impl.BucketServiceImpl;
+import com.epam.datalab.backendapi.service.impl.ComputationalServiceImpl;
+import com.epam.datalab.backendapi.service.impl.EndpointServiceImpl;
+import com.epam.datalab.backendapi.service.impl.EnvironmentServiceImpl;
+import com.epam.datalab.backendapi.service.impl.ExploratoryServiceImpl;
+import com.epam.datalab.backendapi.service.impl.GitCredentialServiceImpl;
+import com.epam.datalab.backendapi.service.impl.GuacamoleServiceImpl;
+import com.epam.datalab.backendapi.service.impl.ImageExploratoryServiceImpl;
+import com.epam.datalab.backendapi.service.impl.InactivityServiceImpl;
+import com.epam.datalab.backendapi.service.impl.LibraryServiceImpl;
+import com.epam.datalab.backendapi.service.impl.MavenCentralLibraryService;
+import com.epam.datalab.backendapi.service.impl.ProjectServiceImpl;
+import com.epam.datalab.backendapi.service.impl.ReuploadKeyServiceImpl;
+import com.epam.datalab.backendapi.service.impl.SchedulerJobServiceImpl;
+import com.epam.datalab.backendapi.service.impl.SystemInfoServiceImpl;
+import com.epam.datalab.backendapi.service.impl.UserGroupServiceImpl;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.mongo.MongoService;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.DockerAPI;
+import com.google.inject.name.Names;
+import io.dropwizard.auth.Authorizer;
+import io.dropwizard.client.JerseyClientBuilder;
+import io.dropwizard.setup.Environment;
+import org.eclipse.jetty.servlets.CrossOriginFilter;
+import org.glassfish.jersey.logging.LoggingFeature;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.FilterRegistration;
+import javax.ws.rs.client.Client;
+import java.util.EnumSet;
+
+/**
+ * Mock class for an application configuration of SelfService for developer mode.
+ */
+public class DevModule extends ModuleBase<SelfServiceApplicationConfiguration> implements SecurityAPI, DockerAPI {
+
+    public static final String TOKEN = "token123";
+
+    /**
+     * Instantiates an application configuration of SelfService for developer mode.
+     *
+     * @param configuration application configuration of SelfService.
+     * @param environment   environment of SelfService.
+     */
+    DevModule(SelfServiceApplicationConfiguration configuration, Environment environment) {
+        super(configuration, environment);
+    }
+
+    @Override
+    protected void configure() {
+        configureCors(environment);
+        final Client httpClient =
+                new JerseyClientBuilder(environment)
+                        .using(configuration.getJerseyClientConfiguration())
+                        .build("httpClient")
+                        .register(new LoggingFeature());
+        bind(SecurityService.class).to(SecurityServiceImpl.class);
+        bind(KeycloakService.class).to(KeycloakServiceImpl.class);
+        bind(Client.class).toInstance(httpClient);
+        bind(SelfServiceApplicationConfiguration.class).toInstance(configuration);
+        bind(MongoService.class).toInstance(configuration.getMongoFactory().build(environment));
+        bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.PROVISIONING_SERVICE_NAME))
+                .toInstance(configuration.getProvisioningFactory()
+                        .build(environment, ServiceConsts.PROVISIONING_SERVICE_NAME));
+        bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.BUCKET_SERVICE_NAME))
+                .toInstance(configuration.getBucketFactory()
+                        .build(environment, ServiceConsts.BUCKET_SERVICE_NAME));
+        bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.BILLING_SERVICE_NAME))
+                .toInstance(configuration.getBillingFactory()
+                        .build(environment, ServiceConsts.BILLING_SERVICE_NAME));
+        bind(ImageExploratoryService.class).to(ImageExploratoryServiceImpl.class);
+        bind(ImageExploratoryDAO.class).to(ImageExploratoryDAOImpl.class);
+        bind(BackupService.class).to(BackupServiceImpl.class);
+        bind(BackupDAO.class).to(BackupDAOImpl.class);
+        bind(ExploratoryService.class).to(ExploratoryServiceImpl.class);
+        bind(TagService.class).to(TagServiceImpl.class);
+        bind(InactivityService.class).to(InactivityServiceImpl.class);
+        bind(Authorizer.class).to(SelfServiceSecurityAuthorizer.class);
+        bind(AccessKeyService.class).to(AccessKeyServiceImpl.class);
+        bind(GitCredentialService.class).to(GitCredentialServiceImpl.class);
+        bind(ComputationalService.class).to(ComputationalServiceImpl.class);
+        bind(LibraryService.class).to(LibraryServiceImpl.class);
+        bind(SchedulerJobService.class).to(SchedulerJobServiceImpl.class);
+        bind(EnvironmentService.class).to(EnvironmentServiceImpl.class);
+        bind(ReuploadKeyService.class).to(ReuploadKeyServiceImpl.class);
+        bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.MAVEN_SEARCH_API))
+                .toInstance(configuration.getMavenApiFactory().build(environment, ServiceConsts.MAVEN_SEARCH_API));
+
+        bind(ExternalLibraryService.class).to(MavenCentralLibraryService.class);
+        bind(SystemInfoService.class).to(SystemInfoServiceImpl.class);
+        bind(UserGroupService.class).to(UserGroupServiceImpl.class);
+        bind(UserRoleService.class).to(UserRoleServiceImpl.class);
+        bind(UserRoleDAO.class).to(UserRoleDAOImpl.class);
+        bind(UserGroupDAO.class).to(UserGroupDAOImpl.class);
+        bind(ApplicationSettingService.class).to(ApplicationSettingServiceImpl.class);
+        bind(UserSettingService.class).to(UserSettingServiceImpl.class);
+        bind(GuacamoleService.class).to(GuacamoleServiceImpl.class);
+        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);
+    }
+
+    private void configureCors(Environment environment) {
+        final FilterRegistration.Dynamic cors =
+                environment.servlets().addFilter("CORS", CrossOriginFilter.class);
+
+        cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
+        cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin," +
+                "Authorization");
+        cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "OPTIONS,GET,PUT,POST,DELETE,HEAD");
+        cors.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "true");
+
+        cors.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
+
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/ModuleFactory.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/ModuleFactory.java
new file mode 100644
index 0000000..ce1213a
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/ModuleFactory.java
@@ -0,0 +1,51 @@
+/*
+ * 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.datalab.backendapi.modules;
+
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.cloud.CloudModule;
+import com.google.inject.AbstractModule;
+import io.dropwizard.setup.Environment;
+
+public class ModuleFactory {
+
+    private ModuleFactory() {
+    }
+
+    /**
+     * Instantiates an application configuration of SelfService for production or tests if
+     * the mock property of configuration is set to <b>true</b> and method
+     * {@link SelfServiceApplicationConfiguration#isMocked()}
+     * returns <b>true</b> value.
+     *
+     * @param configuration application configuration of SelfService.
+     * @param environment   environment of SelfService.
+     */
+    public static AbstractModule getModule(SelfServiceApplicationConfiguration configuration, Environment
+            environment) {
+        return configuration.isDevMode()
+                ? new DevModule(configuration, environment)
+                : new ProductionModule(configuration, environment);
+    }
+
+    public static CloudModule getCloudProviderModule(SelfServiceApplicationConfiguration configuration) {
+        return new CloudProviderModule(configuration);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/ProductionModule.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/ProductionModule.java
new file mode 100644
index 0000000..0d01c4d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/ProductionModule.java
@@ -0,0 +1,176 @@
+/*
+ * 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.datalab.backendapi.modules;
+
+import com.epam.datalab.ModuleBase;
+import com.epam.datalab.backendapi.auth.SelfServiceSecurityAuthorizer;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.AuditDAO;
+import com.epam.datalab.backendapi.dao.AuditDAOImpl;
+import com.epam.datalab.backendapi.dao.BackupDAO;
+import com.epam.datalab.backendapi.dao.BackupDAOImpl;
+import com.epam.datalab.backendapi.dao.BaseBillingDAO;
+import com.epam.datalab.backendapi.dao.BillingDAO;
+import com.epam.datalab.backendapi.dao.EndpointDAO;
+import com.epam.datalab.backendapi.dao.EndpointDAOImpl;
+import com.epam.datalab.backendapi.dao.ImageExploratoryDAO;
+import com.epam.datalab.backendapi.dao.ImageExploratoryDAOImpl;
+import com.epam.datalab.backendapi.dao.ProjectDAO;
+import com.epam.datalab.backendapi.dao.ProjectDAOImpl;
+import com.epam.datalab.backendapi.dao.UserGroupDAO;
+import com.epam.datalab.backendapi.dao.UserGroupDAOImpl;
+import com.epam.datalab.backendapi.dao.UserRoleDAO;
+import com.epam.datalab.backendapi.dao.UserRoleDAOImpl;
+import com.epam.datalab.backendapi.service.AccessKeyService;
+import com.epam.datalab.backendapi.service.ApplicationSettingService;
+import com.epam.datalab.backendapi.service.ApplicationSettingServiceImpl;
+import com.epam.datalab.backendapi.service.AuditService;
+import com.epam.datalab.backendapi.service.BackupService;
+import com.epam.datalab.backendapi.service.BucketService;
+import com.epam.datalab.backendapi.service.ComputationalService;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.EnvironmentService;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.ExternalLibraryService;
+import com.epam.datalab.backendapi.service.GitCredentialService;
+import com.epam.datalab.backendapi.service.GuacamoleService;
+import com.epam.datalab.backendapi.service.ImageExploratoryService;
+import com.epam.datalab.backendapi.service.InactivityService;
+import com.epam.datalab.backendapi.service.KeycloakService;
+import com.epam.datalab.backendapi.service.KeycloakServiceImpl;
+import com.epam.datalab.backendapi.service.LibraryService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.service.ReuploadKeyService;
+import com.epam.datalab.backendapi.service.SchedulerJobService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import com.epam.datalab.backendapi.service.SecurityServiceImpl;
+import com.epam.datalab.backendapi.service.SystemInfoService;
+import com.epam.datalab.backendapi.service.TagService;
+import com.epam.datalab.backendapi.service.TagServiceImpl;
+import com.epam.datalab.backendapi.service.UserGroupService;
+import com.epam.datalab.backendapi.service.UserRoleService;
+import com.epam.datalab.backendapi.service.UserRoleServiceImpl;
+import com.epam.datalab.backendapi.service.UserSettingService;
+import com.epam.datalab.backendapi.service.UserSettingServiceImpl;
+import com.epam.datalab.backendapi.service.impl.AccessKeyServiceImpl;
+import com.epam.datalab.backendapi.service.impl.AuditServiceImpl;
+import com.epam.datalab.backendapi.service.impl.BackupServiceImpl;
+import com.epam.datalab.backendapi.service.impl.BucketServiceImpl;
+import com.epam.datalab.backendapi.service.impl.ComputationalServiceImpl;
+import com.epam.datalab.backendapi.service.impl.EndpointServiceImpl;
+import com.epam.datalab.backendapi.service.impl.EnvironmentServiceImpl;
+import com.epam.datalab.backendapi.service.impl.ExploratoryServiceImpl;
+import com.epam.datalab.backendapi.service.impl.GitCredentialServiceImpl;
+import com.epam.datalab.backendapi.service.impl.GuacamoleServiceImpl;
+import com.epam.datalab.backendapi.service.impl.ImageExploratoryServiceImpl;
+import com.epam.datalab.backendapi.service.impl.InactivityServiceImpl;
+import com.epam.datalab.backendapi.service.impl.LibraryServiceImpl;
+import com.epam.datalab.backendapi.service.impl.MavenCentralLibraryService;
+import com.epam.datalab.backendapi.service.impl.ProjectServiceImpl;
+import com.epam.datalab.backendapi.service.impl.ReuploadKeyServiceImpl;
+import com.epam.datalab.backendapi.service.impl.SchedulerJobServiceImpl;
+import com.epam.datalab.backendapi.service.impl.SystemInfoServiceImpl;
+import com.epam.datalab.backendapi.service.impl.UserGroupServiceImpl;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.mongo.MongoService;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.name.Names;
+import io.dropwizard.auth.Authorizer;
+import io.dropwizard.client.JerseyClientBuilder;
+import io.dropwizard.setup.Environment;
+import org.glassfish.jersey.logging.LoggingFeature;
+
+import javax.ws.rs.client.Client;
+
+/**
+ * Production class for an application configuration of SelfService.
+ */
+public class ProductionModule extends ModuleBase<SelfServiceApplicationConfiguration> {
+
+    /**
+     * Instantiates an application configuration of SelfService for production environment.
+     *
+     * @param configuration application configuration of SelfService.
+     * @param environment   environment of SelfService.
+     */
+    public ProductionModule(SelfServiceApplicationConfiguration configuration, Environment environment) {
+        super(configuration, environment);
+    }
+
+    @Override
+    protected void configure() {
+        final Client httpClient =
+                new JerseyClientBuilder(environment)
+                        .using(configuration.getJerseyClientConfiguration())
+                        .build("httpClient")
+                        .register(new LoggingFeature());
+        bind(SelfServiceApplicationConfiguration.class).toInstance(configuration);
+        bind(MongoService.class).toInstance(configuration.getMongoFactory().build(environment));
+        bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.SECURITY_SERVICE_NAME))
+                .toInstance(configuration.getSecurityFactory().build(environment, ServiceConsts
+                        .SECURITY_SERVICE_NAME));
+        bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.PROVISIONING_SERVICE_NAME))
+                .toInstance(configuration.getProvisioningFactory().build(environment, ServiceConsts
+                        .PROVISIONING_SERVICE_NAME));
+        bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.BUCKET_SERVICE_NAME))
+                .toInstance(configuration.getBucketFactory().build(environment, ServiceConsts
+                        .BUCKET_SERVICE_NAME));
+        bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.BILLING_SERVICE_NAME))
+                .toInstance(configuration.getBillingFactory()
+                        .build(environment, ServiceConsts.BILLING_SERVICE_NAME));
+        bind(ImageExploratoryService.class).to(ImageExploratoryServiceImpl.class);
+        bind(ImageExploratoryDAO.class).to(ImageExploratoryDAOImpl.class);
+        bind(BackupService.class).to(BackupServiceImpl.class);
+        bind(BackupDAO.class).to(BackupDAOImpl.class);
+        bind(ExploratoryService.class).to(ExploratoryServiceImpl.class);
+        bind(Authorizer.class).to(SelfServiceSecurityAuthorizer.class);
+        bind(AccessKeyService.class).to(AccessKeyServiceImpl.class);
+        bind(GitCredentialService.class).to(GitCredentialServiceImpl.class);
+        bind(ComputationalService.class).to(ComputationalServiceImpl.class);
+        bind(LibraryService.class).to(LibraryServiceImpl.class);
+        bind(SchedulerJobService.class).to(SchedulerJobServiceImpl.class);
+        bind(EnvironmentService.class).to(EnvironmentServiceImpl.class);
+        bind(ReuploadKeyService.class).to(ReuploadKeyServiceImpl.class);
+        bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.MAVEN_SEARCH_API))
+                .toInstance(configuration.getMavenApiFactory().build(environment, ServiceConsts.MAVEN_SEARCH_API));
+        bind(ExternalLibraryService.class).to(MavenCentralLibraryService.class);
+        bind(SystemInfoService.class).to(SystemInfoServiceImpl.class);
+        bind(UserGroupService.class).to(UserGroupServiceImpl.class);
+        bind(UserRoleService.class).to(UserRoleServiceImpl.class);
+        bind(UserRoleDAO.class).to(UserRoleDAOImpl.class);
+        bind(UserGroupDAO.class).to(UserGroupDAOImpl.class);
+        bind(InactivityService.class).to(InactivityServiceImpl.class);
+        bind(ApplicationSettingService.class).to(ApplicationSettingServiceImpl.class);
+        bind(UserSettingService.class).to(UserSettingServiceImpl.class);
+        bind(GuacamoleService.class).to(GuacamoleServiceImpl.class);
+        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);
+        bind(KeycloakService.class).to(KeycloakServiceImpl.class);
+        bind(Client.class).toInstance(httpClient);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ApplicationSettingResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ApplicationSettingResource.java
new file mode 100644
index 0000000..8761068
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ApplicationSettingResource.java
@@ -0,0 +1,73 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.ApplicationSettingService;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.annotation.security.RolesAllowed;
+import javax.validation.constraints.Min;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Slf4j
+@Path("/settings")
+@RolesAllowed("/api/settings")
+public class ApplicationSettingResource {
+
+
+	private final ApplicationSettingService settingService;
+
+	@Inject
+	public ApplicationSettingResource(ApplicationSettingService settingService) {
+		this.settingService = settingService;
+	}
+
+	@PUT
+	@Path("budget/{maxBudgetAllowed}")
+	public Response setMaxBudget(@Auth UserInfo userInfo,
+								 @PathParam("maxBudgetAllowed") @Min(1) Long maxBudget) {
+		settingService.setMaxBudget(maxBudget);
+		return Response.noContent().build();
+	}
+
+	@DELETE
+	@Path("budget")
+	public Response removeAllowedBudget(@Auth UserInfo userInfo) {
+		log.debug("User {} is removing max budget application setting", userInfo.getName());
+		settingService.removeMaxBudget();
+		return Response.noContent().build();
+	}
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response getSettings(@Auth UserInfo userInfo) {
+		return Response.ok(settingService.getSettings()).build();
+
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/AuditResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/AuditResource.java
new file mode 100644
index 0000000..aa04fd0
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/AuditResource.java
@@ -0,0 +1,70 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.AuditCreateDTO;
+import com.epam.datalab.backendapi.service.AuditService;
+import com.epam.datalab.model.StringList;
+import com.google.inject.Inject;
+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.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("/audit")
+public class AuditResource {
+    private final AuditService auditService;
+
+    @Inject
+    public AuditResource(AuditService auditService) {
+        this.auditService = auditService;
+    }
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    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,
+                             @QueryParam("users") StringList users,
+                             @QueryParam("projects") StringList projects,
+                             @QueryParam("resource-names") StringList resourceNames,
+                             @QueryParam("resource-types") StringList resourceTypes,
+                             @QueryParam("date-start") String dateStart,
+                             @QueryParam("date-end") String dateEnd,
+                             @QueryParam("page-number") int pageNumber,
+                             @QueryParam("page-size") int pageSize) {
+        return Response
+                .ok(auditService.getAudit(users, projects, resourceNames, resourceTypes, dateStart, dateEnd, pageNumber, pageSize))
+                .build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/BackupResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/BackupResource.java
new file mode 100644
index 0000000..3853115
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/BackupResource.java
@@ -0,0 +1,90 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.resources.dto.BackupFormDTO;
+import com.epam.datalab.backendapi.service.BackupService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.dto.backup.EnvBackupDTO;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.annotation.security.RolesAllowed;
+import javax.validation.Valid;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.UUID;
+
+
+@Slf4j
+@Path("/infrastructure/backup")
+@RolesAllowed("/api/infrastructure/backup")
+public class BackupResource {
+
+	private final BackupService backupService;
+	private final RequestBuilder requestBuilder;
+	private final RequestId requestId;
+
+	@Inject
+	public BackupResource(BackupService backupService, RequestBuilder requestBuilder, RequestId requestId) {
+		this.backupService = backupService;
+		this.requestBuilder = requestBuilder;
+		this.requestId = requestId;
+	}
+
+	@POST
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Produces(MediaType.TEXT_PLAIN)
+	public Response createBackup(@Auth UserInfo userInfo,
+								 @Valid BackupFormDTO backupFormDTO) {
+		log.debug("Creating backup for user {} with parameters {}", userInfo.getName(), backupFormDTO);
+		final EnvBackupDTO dto = requestBuilder.newBackupCreate(backupFormDTO, UUID.randomUUID().toString());
+		final String uuid = backupService.createBackup(dto, userInfo);
+		requestId.put(userInfo.getName(), uuid);
+		return Response.accepted(uuid).build();
+	}
+
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response getBackups(@Auth UserInfo userInfo) {
+		log.debug("Getting backups for user {}", userInfo.getName());
+		return Response.ok(backupService.getBackups(userInfo.getName())).build();
+	}
+
+	@GET
+	@Path("{id}")
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response getBackup(@Auth UserInfo userInfo,
+							  @PathParam("id") String id) {
+		log.debug("Getting backup with id {} for user {}", id, userInfo.getName());
+		return Response.ok(backupService.getBackup(userInfo.getName(), id)).build();
+	}
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/BillingResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/BillingResource.java
new file mode 100644
index 0000000..2f467a2
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/BillingResource.java
@@ -0,0 +1,72 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.BillingFilter;
+import com.epam.datalab.backendapi.service.BillingService;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("/billing")
+@Consumes(MediaType.APPLICATION_JSON)
+public class BillingResource {
+
+    private final BillingService billingService;
+
+    @Inject
+    public BillingResource(BillingService billingService) {
+        this.billingService = billingService;
+    }
+
+    @GET
+    @Path("/quota")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getQuota(@Auth UserInfo userInfo) {
+        return Response.ok(billingService.getQuotas(userInfo)).build();
+    }
+
+    @POST
+    @Path("/report")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getBillingReport(@Auth UserInfo userInfo, @Valid @NotNull BillingFilter filter) {
+        return Response.ok(billingService.getBillingReport(userInfo, filter)).build();
+    }
+
+    @POST
+    @Path("/report/download")
+    @Produces(MediaType.APPLICATION_OCTET_STREAM)
+    public Response downloadBillingReport(@Auth UserInfo userInfo, @Valid @NotNull BillingFilter filter) {
+        return Response.ok(billingService.downloadReport(userInfo, filter))
+                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"billing-report.csv\"")
+                .build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/BucketResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/BucketResource.java
new file mode 100644
index 0000000..26494a0
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/BucketResource.java
@@ -0,0 +1,163 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.BucketDeleteDTO;
+import com.epam.datalab.backendapi.resources.dto.FolderUploadDTO;
+import com.epam.datalab.backendapi.service.BucketService;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.fileupload.FileItemIterator;
+import org.apache.commons.fileupload.FileItemStream;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.commons.fileupload.util.Streams;
+
+import javax.annotation.security.RolesAllowed;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+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.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+import java.nio.file.Paths;
+
+@Path("/bucket")
+@Slf4j
+public class BucketResource {
+    private static final String AUDIT_FOLDER_UPLOAD_MESSAGE = "Upload folder: %s";
+    private static final String AUDIT_FILE_UPLOAD_MESSAGE = "Upload file: %s";
+    private static final String AUDIT_FILE_DOWNLOAD_MESSAGE = "Download file: %s";
+    private static final String AUDIT_FILE_DELETE_MESSAGE = "Delete file: %s";
+    private static final String OBJECT_FORM_FIELD = "object";
+    private static final String BUCKET_FORM_FIELD = "bucket";
+    private static final String ENDPOINT_FORM_FIELD = "endpoint";
+    private static final String SIZE_FORM_FIELD = "size";
+
+    private final BucketService bucketService;
+
+    @Inject
+    public BucketResource(BucketService bucketService) {
+        this.bucketService = bucketService;
+    }
+
+    @GET
+    @Path("/{bucket}/endpoint/{endpoint}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @RolesAllowed("/api/bucket/view")
+    public Response getListOfObjects(@Auth UserInfo userInfo,
+                                     @PathParam("bucket") String bucket,
+                                     @PathParam("endpoint") String endpoint) {
+        return Response.ok(bucketService.getObjects(userInfo, bucket, endpoint)).build();
+    }
+
+    @POST
+    @Path("/upload")
+    @Consumes(MediaType.MULTIPART_FORM_DATA)
+    @Produces(MediaType.APPLICATION_JSON)
+    @RolesAllowed("/api/bucket/upload")
+    public Response uploadObject(@Auth UserInfo userInfo, @Context HttpServletRequest request) {
+        upload(userInfo, request);
+        return Response.ok().build();
+    }
+
+    @POST
+    @Path("/folder/upload")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @RolesAllowed("/api/bucket/upload")
+    public Response uploadFolder(@Auth UserInfo userInfo, @Valid FolderUploadDTO dto) {
+        bucketService.uploadFolder(userInfo, dto.getBucket(), dto.getFolder(), dto.getEndpoint(), String.format(AUDIT_FOLDER_UPLOAD_MESSAGE, dto.getFolder()));
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/{bucket}/object/{object}/endpoint/{endpoint}/download")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_OCTET_STREAM)
+    @RolesAllowed("/api/bucket/download")
+    public Response downloadObject(@Auth UserInfo userInfo, @Context HttpServletResponse resp,
+                                   @PathParam("bucket") String bucket,
+                                   @PathParam("object") String object,
+                                   @PathParam("endpoint") String endpoint) {
+        bucketService.downloadObject(userInfo, bucket, object, endpoint, resp, String.format(AUDIT_FILE_DOWNLOAD_MESSAGE, object));
+        return Response.ok()
+                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + Paths.get(object).getFileName() + "\"")
+                .build();
+    }
+
+    @POST
+    @Path("/objects/delete")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @RolesAllowed("/api/bucket/delete")
+    public Response deleteObject(@Auth UserInfo userInfo, @Valid BucketDeleteDTO bucketDto) {
+        final String listOfDeletedObject = String.join(", ", bucketDto.getObjects());
+        bucketService.deleteObjects(userInfo, bucketDto.getBucket(), bucketDto.getObjects(), bucketDto.getEndpoint(), String.format(AUDIT_FILE_DELETE_MESSAGE, listOfDeletedObject));
+        return Response.ok().build();
+    }
+
+    private void upload(UserInfo userInfo, HttpServletRequest request) {
+        String object = null;
+        String bucket = null;
+        String endpoint = null;
+        long fileSize = 0;
+
+        ServletFileUpload upload = new ServletFileUpload();
+        try {
+            FileItemIterator iterStream = upload.getItemIterator(request);
+            while (iterStream.hasNext()) {
+                FileItemStream item = iterStream.next();
+                try (InputStream stream = item.openStream()) {
+                    if (item.isFormField()) {
+                        if (OBJECT_FORM_FIELD.equals(item.getFieldName())) {
+                            object = Streams.asString(stream);
+                        } else if (BUCKET_FORM_FIELD.equals(item.getFieldName())) {
+                            bucket = Streams.asString(stream);
+                        } else if (ENDPOINT_FORM_FIELD.equals(item.getFieldName())) {
+                            endpoint = Streams.asString(stream);
+                        } else if (SIZE_FORM_FIELD.equals(item.getFieldName())) {
+                            fileSize = Long.parseLong(Streams.asString(stream));
+                        }
+                    } else {
+                        bucketService.uploadObject(userInfo, bucket, object, endpoint, stream, item.getContentType(), fileSize, String.format(AUDIT_FILE_UPLOAD_MESSAGE, object));
+                    }
+                } catch (Exception e) {
+                    log.error("Cannot upload object {} to bucket {}. {}", object, bucket, e.getMessage(), e);
+                    throw new DatalabException(String.format("Cannot upload object %s to bucket %s. %s", object, bucket, e.getMessage()));
+                }
+            }
+        } catch (Exception e) {
+            log.error("User {} cannot upload object {} to bucket {}. {}", userInfo.getName(), object, bucket, e.getMessage(), e);
+            throw new DatalabException(String.format("User %s cannot upload object %s to bucket %s. %s", userInfo.getName(), object, bucket, e.getMessage()));
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EndpointResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EndpointResource.java
new file mode 100644
index 0000000..48a1061
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EndpointResource.java
@@ -0,0 +1,151 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.EndpointResourcesDTO;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.rest.dto.ErrorDTO;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.headers.Header;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+import javax.annotation.security.RolesAllowed;
+import javax.validation.Valid;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.net.URI;
+
+@Path("endpoint")
+@RolesAllowed("/api/endpoint")
+public class EndpointResource {
+
+    private final EndpointService endpointService;
+    @Context
+    private UriInfo uriInfo;
+
+    @Inject
+    public EndpointResource(EndpointService endpointService) {
+        this.endpointService = endpointService;
+    }
+
+    @Operation(summary = "Create endpoint", tags = "endpoint")
+    @ApiResponse(responseCode = "201", description = "Endpoint is successfully created",
+            headers =
+            @Header(required = true, name = "Location", description = "URI of created endpoint resource",
+                    schema = @Schema(type = "string")))
+    @ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
+            MediaType.APPLICATION_JSON,
+            schema = @Schema(implementation = ErrorDTO.class)))
+    @ApiResponse(responseCode = "409", description = "Endpoint with passed name already exist in system",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON,
+                    schema = @Schema(implementation = ErrorDTO.class)))
+    @Consumes(MediaType.APPLICATION_JSON)
+    @POST
+    public Response createEndpoint(@Parameter(hidden = true) @Auth UserInfo userInfo, @Valid EndpointDTO endpointDTO) {
+        endpointService.create(userInfo, endpointDTO.getName(), endpointDTO);
+        final URI uri = uriInfo.getRequestUriBuilder().path(endpointDTO.getName()).build();
+        return Response
+                .ok()
+                .location(uri)
+                .build();
+    }
+
+    @Operation(summary = "Get endpoint info", tags = "endpoint")
+    @ApiResponse(responseCode = "200", description = "Return information about endpoint",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
+            @Schema(implementation = EndpointDTO.class)))
+    @ApiResponse(responseCode = "404", description = "Endpoint with passed name not found",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON,
+                    schema = @Schema(implementation = ErrorDTO.class)))
+    @GET
+    @Path("{name}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getEndpoint(@Parameter(hidden = true) @Auth UserInfo userInfo,
+                                @Parameter(description = "Endpoint name")
+                                @PathParam("name") String name) {
+        return Response.ok(endpointService.get(name)).build();
+    }
+
+    @Operation(summary = "Get endpoints available in system", tags = "endpoint")
+    @ApiResponse(responseCode = "200", description = "Return information about endpoints",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
+            @Schema(implementation = EndpointDTO.class)))
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getEndpoints(@Parameter(hidden = true) @Auth UserInfo userInfo) {
+        return Response.ok(endpointService.getEndpoints()).build();
+    }
+
+    @Operation(summary = "Get resources related to the endpoint", tags = "endpoint")
+    @ApiResponse(responseCode = "200", description = "Return information about resources of endpoint",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
+            @Schema(implementation = EndpointResourcesDTO.class)))
+    @GET
+    @Path("{name}/resources")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getEndpointResources(@Parameter(hidden = true) @Auth UserInfo userInfo,
+                                         @Parameter(description = "Endpoint name")
+                                         @PathParam("name") String name) {
+        return Response.ok(endpointService.getEndpointResources(name)).build();
+    }
+
+    @Operation(summary = "Remove endpoint", tags = "endpoint")
+    @ApiResponse(responseCode = "200", description = "Endpoint is successfully removed")
+    @ApiResponse(responseCode = "404", description = "Endpoint with passed name not found",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON,
+                    schema = @Schema(implementation = ErrorDTO.class)))
+    @DELETE
+    @Path("{name}")
+    public Response removeEndpoint(@Parameter(hidden = true) @Auth UserInfo userInfo,
+                                   @Parameter(description = "Endpoint name")
+                                   @PathParam("name") String name) {
+        endpointService.remove(userInfo, name);
+        return Response.ok().build();
+    }
+
+    @Operation(summary = "Check whether endpoint url is valid", tags = "endpoint")
+    @ApiResponse(responseCode = "200", description = "Valid endpoint url")
+    @ApiResponse(responseCode = "404", description = "Endpoint url is not valid")
+    @GET
+    @Path("url/{url}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response checkEndpointUrl(@Parameter(hidden = true) @Auth UserInfo userInfo,
+                                     @Parameter(description = "Endpoint url")
+                                     @PathParam("url") String url) {
+        endpointService.checkUrl(userInfo, url);
+        return Response.ok().build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EnvironmentResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EnvironmentResource.java
new file mode 100644
index 0000000..b4b1418
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EnvironmentResource.java
@@ -0,0 +1,110 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.EnvironmentService;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("environment")
+@Slf4j
+@RolesAllowed("environment/*")
+public class EnvironmentResource {
+
+    private EnvironmentService environmentService;
+
+    @Inject
+    public EnvironmentResource(EnvironmentService environmentService) {
+        this.environmentService = environmentService;
+    }
+
+    @GET
+    @Path("all")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getAllEnv(@Auth UserInfo userInfo) {
+        log.debug("Admin {} requested information about all user's environment", userInfo.getName());
+        return Response.ok(environmentService.getAllEnv(userInfo)).build();
+    }
+
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("stop/{projectName}/{exploratoryName}")
+    public Response stopNotebook(@Auth UserInfo userInfo, @NotEmpty String user,
+                                 @PathParam("projectName") String projectName,
+                                 @PathParam("exploratoryName") String exploratoryName) {
+        log.info("Admin {} is stopping notebook {} of user {}", userInfo.getName(), exploratoryName, user);
+        environmentService.stopExploratory(userInfo, user, projectName, exploratoryName);
+        return Response.ok().build();
+    }
+
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("stop/{projectName}/{exploratoryName}/{computationalName}")
+    public Response stopCluster(@Auth UserInfo userInfo, @NotEmpty String user,
+                                @PathParam("projectName") String projectName,
+                                @PathParam("exploratoryName") String exploratoryName,
+                                @PathParam("computationalName") String computationalName) {
+        log.info("Admin {} is stopping computational resource {} affiliated with exploratory {} of user {}",
+                userInfo.getName(), computationalName, exploratoryName, user);
+        environmentService.stopComputational(userInfo, user, projectName, exploratoryName, computationalName);
+        return Response.ok().build();
+    }
+
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("terminate/{projectName}/{exploratoryName}")
+    public Response terminateNotebook(@Auth UserInfo userInfo, @NotEmpty String user,
+                                      @PathParam("projectName") String projectName,
+                                      @PathParam("exploratoryName") String exploratoryName) {
+        log.info("Admin {} is terminating notebook {} of user {}", userInfo.getName(), exploratoryName, user);
+        environmentService.terminateExploratory(userInfo, user, projectName, exploratoryName);
+        return Response.ok().build();
+    }
+
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("terminate/{projectName}/{exploratoryName}/{computationalName}")
+    public Response terminateCluster(@Auth UserInfo userInfo, @NotEmpty String user,
+                                     @PathParam("projectName") String projectName,
+                                     @PathParam("exploratoryName") String exploratoryName,
+                                     @PathParam("computationalName") String computationalName) {
+        log.info("Admin {} is terminating computational resource {} affiliated with exploratory {} of user {}",
+                userInfo.getName(), computationalName, exploratoryName, user);
+        environmentService.terminateComputational(userInfo, user, projectName, exploratoryName, computationalName);
+        return Response.ok().build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ExploratoryResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ExploratoryResource.java
new file mode 100644
index 0000000..f9896b7
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ExploratoryResource.java
@@ -0,0 +1,175 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.ExploratoryActionFormDTO;
+import com.epam.datalab.backendapi.resources.dto.ExploratoryCreateFormDTO;
+import com.epam.datalab.backendapi.roles.RoleType;
+import com.epam.datalab.backendapi.roles.UserRoles;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.model.exploratory.Exploratory;
+import com.epam.datalab.rest.contracts.ExploratoryAPI;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+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.List;
+
+/**
+ * Provides the REST API for the exploratory.
+ */
+@Path("/infrastructure_provision/exploratory_environment")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ExploratoryResource implements ExploratoryAPI {
+
+    private ExploratoryService exploratoryService;
+
+    @Inject
+    public ExploratoryResource(ExploratoryService exploratoryService) {
+        this.exploratoryService = exploratoryService;
+    }
+
+    @GET
+    public Response getExploratoryPopUp(@Auth UserInfo userInfo) {
+        return Response.ok(exploratoryService.getUserInstances(userInfo)).build();
+    }
+
+    /**
+     * Creates the exploratory environment for user.
+     *
+     * @param userInfo user info.
+     * @param formDTO  description for the exploratory environment.
+     * @return {@link Response.Status#OK} request for provisioning service has been accepted.<br>
+     * {@link Response.Status#FOUND} request for provisioning service has been duplicated.
+     */
+    @PUT
+    public Response create(@Auth UserInfo userInfo,
+                           @Valid @NotNull ExploratoryCreateFormDTO formDTO) {
+        log.debug("Creating exploratory environment {} with name {} for user {}",
+                formDTO.getImage(), formDTO.getName(), userInfo.getName());
+        if (!UserRoles.checkAccess(userInfo, RoleType.EXPLORATORY, formDTO.getImage(), userInfo.getRoles())) {
+            log.warn("Unauthorized attempt to create a {} by user {}", formDTO.getImage(), userInfo.getName());
+            throw new DatalabException("You do not have the privileges to create a " + formDTO.getTemplateName());
+        }
+        String uuid = exploratoryService.create(userInfo, getExploratory(formDTO), formDTO.getProject(), formDTO.getName());
+        return Response.ok(uuid).build();
+
+    }
+
+
+    /**
+     * Starts exploratory environment for user.
+     *
+     * @param userInfo user info.
+     * @param formDTO  description of exploratory action.
+     * @return Invocation response as JSON string.
+     */
+    @POST
+    public String start(@Auth UserInfo userInfo,
+                        @Valid @NotNull ExploratoryActionFormDTO formDTO) {
+        log.debug("Starting exploratory environment {} for user {}", formDTO.getNotebookInstanceName(),
+                userInfo.getName());
+        return exploratoryService.start(userInfo, formDTO.getNotebookInstanceName(), formDTO.getProjectName(), null);
+    }
+
+    /**
+     * Stops exploratory environment for user.
+     *
+     * @param userInfo user info.
+     * @param name     name of exploratory environment.
+     * @return Invocation response as JSON string.
+     */
+    @DELETE
+    @Path("/{project}/{name}/stop")
+    public String stop(@Auth UserInfo userInfo,
+                       @PathParam("project") String project,
+                       @PathParam("name") String name) {
+        log.debug("Stopping exploratory environment {} for user {}", name, userInfo.getName());
+        return exploratoryService.stop(userInfo, userInfo.getName(), project, name, null);
+    }
+
+    /**
+     * Terminates exploratory environment for user.
+     *
+     * @param userInfo user info.
+     * @param name     name of exploratory environment.
+     * @return Invocation response as JSON string.
+     */
+    @DELETE
+    @Path("/{project}/{name}/terminate")
+    public String terminate(@Auth UserInfo userInfo,
+                            @PathParam("project") String project,
+                            @PathParam("name") String name) {
+        log.debug("Terminating exploratory environment {} for user {}", name, userInfo.getName());
+        return exploratoryService.terminate(userInfo, userInfo.getName(), project, name, null);
+    }
+
+    @PUT
+    @Path("/{project}/{name}/reconfigure")
+    public Response reconfigureSpark(@Auth UserInfo userInfo,
+                                     @PathParam("project") String project,
+                                     @PathParam("name") String name,
+                                     List<ClusterConfig> config) {
+        log.debug("Updating exploratory {} spark cluster for user {}", name, userInfo.getName());
+        exploratoryService.updateClusterConfig(userInfo, project, name, config);
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/{project}/{name}/cluster/config")
+    public Response getClusterConfig(@Auth UserInfo userInfo,
+                                     @PathParam("project") String project,
+                                     @PathParam("name") String name) {
+        log.debug("Getting exploratory {} spark cluster configuration for user {}", name, userInfo.getName());
+        return Response.ok(exploratoryService.getClusterConfig(userInfo, project, name)).build();
+    }
+
+    private Exploratory getExploratory(ExploratoryCreateFormDTO formDTO) {
+        return Exploratory.builder()
+                .name(formDTO.getName())
+                .dockerImage(formDTO.getImage())
+                .imageName(formDTO.getImageName())
+                .templateName(formDTO.getTemplateName())
+                .version(formDTO.getVersion())
+                .clusterConfig(formDTO.getClusterConfig())
+                .shape(formDTO.getShape())
+                .endpoint(formDTO.getEndpoint())
+                .project(formDTO.getProject())
+                .exploratoryTag(formDTO.getExploratoryTag())
+                .build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/GitCredsResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/GitCredsResource.java
new file mode 100644
index 0000000..2a9cf43
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/GitCredsResource.java
@@ -0,0 +1,78 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.GitCredentialService;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsDTO;
+import com.epam.datalab.rest.contracts.ExploratoryAPI;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Provides the REST API for managing git credentials
+ */
+@Path("/user/git_creds")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class GitCredsResource implements ExploratoryAPI {
+
+    private final GitCredentialService gitCredentialService;
+
+    @Inject
+    public GitCredsResource(GitCredentialService gitCredentialService) {
+        this.gitCredentialService = gitCredentialService;
+    }
+
+    /**
+     * Update GIT credentials for user.
+     *
+     * @param userInfo user info.
+     * @param formDTO  the list of credentials.
+     * @return {@link Response.Status#OK} request for provisioning service has been accepted.<br>
+     */
+    @PUT
+    public Response updateGitCreds(@Auth UserInfo userInfo, @Valid @NotNull ExploratoryGitCredsDTO formDTO) {
+        gitCredentialService.updateGitCredentials(userInfo, formDTO);
+        return Response.ok().build();
+    }
+
+    /**
+     * Returns info about GIT credentials for user.
+     *
+     * @param userInfo user info.
+     */
+    @GET
+    public ExploratoryGitCredsDTO getGitCreds(@Auth UserInfo userInfo) {
+        return gitCredentialService.getGitCredentials(userInfo.getName());
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ImageExploratoryResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ImageExploratoryResource.java
new file mode 100644
index 0000000..95dcdb4
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ImageExploratoryResource.java
@@ -0,0 +1,110 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.resources.dto.ExploratoryImageCreateFormDTO;
+import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.backendapi.service.ImageExploratoryService;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import java.net.URI;
+import java.util.List;
+
+/**
+ * Manages images for exploratory and computational environment
+ */
+@Path("/infrastructure_provision/exploratory_environment/image")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ImageExploratoryResource {
+    private static final String AUDIT_MESSAGE = "Create image: %s";
+
+    private final ImageExploratoryService imageExploratoryService;
+    private final RequestId requestId;
+
+    @Inject
+    public ImageExploratoryResource(ImageExploratoryService imageExploratoryService, RequestId requestId) {
+        this.imageExploratoryService = imageExploratoryService;
+        this.requestId = requestId;
+    }
+
+    @POST
+    public Response createImage(@Auth UserInfo ui,
+                                @Valid @NotNull ExploratoryImageCreateFormDTO formDTO,
+                                @Context UriInfo uriInfo) {
+        log.debug("Creating an image {} for user {}", formDTO, ui.getName());
+        String uuid = imageExploratoryService.createImage(ui, formDTO.getProjectName(), formDTO.getNotebookName(),
+                formDTO.getName(), formDTO.getDescription(), String.format(AUDIT_MESSAGE, formDTO.getName()));
+        requestId.put(ui.getName(), uuid);
+
+        final URI imageUri = UriBuilder.fromUri(uriInfo.getRequestUri())
+                .path(formDTO.getName())
+                .build();
+        return Response.accepted(uuid).location(imageUri).build();
+    }
+
+    @GET
+    public Response getImages(@Auth UserInfo ui,
+                              @QueryParam("docker_image") String dockerImage,
+                              @QueryParam("project") String project,
+                              @QueryParam("endpoint") String endpoint) {
+        log.debug("Getting images for user {}, project {}", ui.getName(), project);
+        final List<ImageInfoRecord> images = imageExploratoryService.getNotFailedImages(ui.getName(), dockerImage,
+                project, endpoint);
+        return Response.ok(images).build();
+    }
+
+    @GET
+    @Path("all")
+    public Response getAllImagesForProject(@Auth UserInfo ui, @NotNull @QueryParam("project") String project) {
+        log.debug("Getting images for user {}, project {}", ui.getName(), project);
+        final List<ImageInfoRecord> images = imageExploratoryService.getImagesForProject(project);
+        return Response.ok(images).build();
+    }
+
+    @GET
+    @Path("{name}")
+    public Response getImage(@Auth UserInfo ui,
+                             @PathParam("name") String name,
+                             @QueryParam("project") String project,
+                             @QueryParam("endpoint") String endpoint) {
+        log.debug("Getting image with name {} for user {}", name, ui.getName());
+        return Response.ok(imageExploratoryService.getImage(ui.getName(), name, project, endpoint)).build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/InfrastructureInfoResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/InfrastructureInfoResource.java
new file mode 100644
index 0000000..725e369
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/InfrastructureInfoResource.java
@@ -0,0 +1,95 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.HealthStatusPageDTO;
+import com.epam.datalab.backendapi.resources.dto.ProjectInfrastructureInfo;
+import com.epam.datalab.backendapi.service.InfrastructureInfoService;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+/**
+ * Provides the REST API for the basic information about infrastructure.
+ */
+@Path("/infrastructure")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class InfrastructureInfoResource {
+
+    private InfrastructureInfoService infrastructureInfoService;
+
+    @Inject
+    public InfrastructureInfoResource(InfrastructureInfoService infrastructureInfoService) {
+        this.infrastructureInfoService = infrastructureInfoService;
+    }
+
+    /**
+     * Return status of self-service.
+     */
+    @GET
+    public Response status() {
+        return Response.status(Response.Status.OK).build();
+    }
+
+    /**
+     * Returns the status of infrastructure: edge.
+     *
+     * @param userInfo user info.
+     */
+    @GET
+    @Path("/status")
+    public HealthStatusPageDTO status(@Auth UserInfo userInfo,
+                                      @QueryParam("full") @DefaultValue("0") int fullReport) {
+        return infrastructureInfoService.getHeathStatus(userInfo);
+    }
+
+    /**
+     * Returns the list of the provisioned user resources.
+     *
+     * @param userInfo user info.
+     */
+    @GET
+    @Path("/info")
+    public List<ProjectInfrastructureInfo> getUserResources(@Auth UserInfo userInfo) {
+        return infrastructureInfoService.getUserResources(userInfo);
+
+    }
+
+    @GET
+    @Path("/meta")
+    public Response getVersion(@Auth UserInfo userInfo) {
+        return Response.ok(infrastructureInfoService.getInfrastructureMetaInfo())
+                .build();
+
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/InfrastructureTemplateResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/InfrastructureTemplateResource.java
new file mode 100644
index 0000000..4e2dafe
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/InfrastructureTemplateResource.java
@@ -0,0 +1,78 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.InfrastructureTemplateService;
+import com.epam.datalab.dto.base.computational.FullComputationalTemplate;
+import com.epam.datalab.dto.imagemetadata.ExploratoryMetadataDTO;
+import com.epam.datalab.rest.contracts.DockerAPI;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * Provides the REST API to retrieve exploratory/computational templates.
+ */
+@Path("/infrastructure_templates")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class InfrastructureTemplateResource implements DockerAPI {
+
+	private InfrastructureTemplateService infrastructureTemplateService;
+
+	@Inject
+	public InfrastructureTemplateResource(InfrastructureTemplateService infrastructureTemplateService) {
+		this.infrastructureTemplateService = infrastructureTemplateService;
+	}
+
+	/**
+	 * Returns the list of the computational resources templates for user.
+	 *
+	 * @param userInfo user info.
+	 */
+	@GET
+	@Path("/{project}/{endpoint}/computational_templates")
+	public Iterable<FullComputationalTemplate> getComputationalTemplates(@Auth UserInfo userInfo,
+																		 @PathParam("project") String project,
+																		 @PathParam("endpoint") String endpoint) {
+		return infrastructureTemplateService.getComputationalTemplates(userInfo, project, endpoint);
+	}
+
+	/**
+	 * Returns the list of the exploratory environment templates for user.
+	 *
+	 * @param userInfo user info.
+	 */
+	@GET
+	@Path("/{project}/{endpoint}/exploratory_templates")
+	public Iterable<ExploratoryMetadataDTO> getExploratoryTemplates(@Auth UserInfo userInfo,
+																	@PathParam("project") String project,
+																	@PathParam("endpoint") String endpoint) {
+		return infrastructureTemplateService.getExploratoryTemplates(userInfo, project, endpoint);
+	}
+}
+
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/KeycloakResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/KeycloakResource.java
new file mode 100644
index 0000000..066037f
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/KeycloakResource.java
@@ -0,0 +1,140 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.KeycloakConfiguration;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.SecurityDAO;
+import com.epam.datalab.backendapi.roles.UserRoles;
+import com.epam.datalab.backendapi.service.KeycloakService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import com.epam.datalab.exceptions.DatalabException;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+import org.keycloak.representations.AccessTokenResponse;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import static java.lang.String.format;
+
+@Path("/oauth")
+@Slf4j
+public class KeycloakResource {
+    private static final String LOGIN_URI_FORMAT = "%s/realms/%s/protocol/openid-connect/auth?client_id=%s" +
+            "&redirect_uri=%s&response_type=code";
+    private static final String KEYCLOAK_LOGOUT_URI_FORMAT = "%s/realms/%s/protocol/openid-connect/logout" +
+            "?redirect_uri=%s";
+    private final SecurityService securityService;
+    private final KeycloakService keycloakService;
+    private final SecurityDAO securityDAO;
+    private final String loginUri;
+    private final String logoutUri;
+    private final String redirectUri;
+    private final boolean defaultAccess;
+
+    @Inject
+    public KeycloakResource(SecurityService securityService, SelfServiceApplicationConfiguration configuration,
+                            SecurityDAO securityDAO, KeycloakService keycloakService) {
+        this.securityDAO = securityDAO;
+        this.defaultAccess = configuration.getRoleDefaultAccess();
+        final KeycloakConfiguration keycloakConfiguration = configuration.getKeycloakConfiguration();
+        this.redirectUri = keycloakConfiguration.getRedirectUri();
+        this.securityService = securityService;
+        this.keycloakService = keycloakService;
+
+        loginUri = format(LOGIN_URI_FORMAT,
+                keycloakConfiguration.getAuthServerUrl(),
+                keycloakConfiguration.getRealm(),
+                keycloakConfiguration.getResource(),
+                redirectUri);
+        logoutUri = format(KEYCLOAK_LOGOUT_URI_FORMAT,
+                keycloakConfiguration.getAuthServerUrl(),
+                keycloakConfiguration.getRealm(),
+                redirectUri);
+    }
+
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public Response getLoginUri() throws URISyntaxException {
+        return Response.ok(new URI(loginUri).toString())
+                .build();
+    }
+
+    @POST
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getUser(@QueryParam("code") String code) {
+        return Response.ok(securityService.getUserInfo(code)).build();
+    }
+
+    @POST
+    @Path("/authorize")
+    public Response authorize(@Auth UserInfo userInfo) {
+        UserRoles.initialize(securityDAO, defaultAccess);
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/logout")
+    public Response getLogoutUrl() throws URISyntaxException {
+        return Response.noContent()
+                .location(new URI(logoutUri))
+                .build();
+    }
+
+    @POST
+    @Path("/refresh/{refresh_token}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response refreshAccessToken(@PathParam("refresh_token") String refreshToken) throws URISyntaxException {
+        AccessTokenResponse tokenResponse;
+        try {
+            tokenResponse = keycloakService.generateAccessToken(refreshToken);
+        } catch (DatalabException e) {
+            log.error("Cannot refresh token due to: {}", e.getMessage(), e);
+            return Response.status(Response.Status.BAD_REQUEST)
+                    .location(new URI(logoutUri))
+                    .build();
+        }
+        return Response.ok(new TokenInfo(tokenResponse.getToken(), tokenResponse.getRefreshToken())).build();
+    }
+
+    class TokenInfo {
+        @JsonProperty("access_token")
+        private final String accessToken;
+        @JsonProperty("refresh_token")
+        private final String refreshToken;
+
+        TokenInfo(String accessToken, String refreshToken) {
+            this.accessToken = accessToken;
+            this.refreshToken = refreshToken;
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/LibExploratoryResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/LibExploratoryResource.java
new file mode 100644
index 0000000..eb16310
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/LibExploratoryResource.java
@@ -0,0 +1,217 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.domain.ExploratoryLibCache;
+import com.epam.datalab.backendapi.resources.dto.LibInfoRecord;
+import com.epam.datalab.backendapi.resources.dto.LibInstallFormDTO;
+import com.epam.datalab.backendapi.resources.dto.LibraryAutoCompleteDTO;
+import com.epam.datalab.backendapi.resources.dto.SearchLibsFormDTO;
+import com.epam.datalab.backendapi.service.ExternalLibraryService;
+import com.epam.datalab.backendapi.service.LibraryService;
+import com.epam.datalab.backendapi.validation.annotation.LibNameValid;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.exploratory.LibInstallDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.bson.Document;
+import org.hibernate.validator.constraints.NotBlank;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Manages libraries for exploratory and computational environment
+ */
+@Path("/infrastructure_provision/exploratory_environment")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class LibExploratoryResource {
+    private static final String AUDIT_MESSAGE = "Install libs: %s";
+
+    private final ExternalLibraryService externalLibraryService;
+    private final ExploratoryDAO exploratoryDAO;
+    private final LibraryService libraryService;
+
+    @Inject
+    public LibExploratoryResource(ExploratoryDAO exploratoryDAO, LibraryService libraryService,
+                                  ExternalLibraryService externalLibraryService) {
+        this.exploratoryDAO = exploratoryDAO;
+        this.libraryService = libraryService;
+        this.externalLibraryService = externalLibraryService;
+    }
+
+    @GET
+    @Path("/lib-groups/exploratory")
+    public Response getExploratoryLibGroupList(@Auth UserInfo userInfo,
+                                               @QueryParam("project") @NotBlank String projectName,
+                                               @QueryParam("exploratory") @NotBlank String exploratoryName) {
+        return Response.ok(libraryService.getExploratoryLibGroups(userInfo, projectName, exploratoryName)).build();
+    }
+
+    @GET
+    @Path("/lib-groups/compute")
+    public Response getComputeLibGroupList(@Auth UserInfo userInfo) {
+        return Response.ok(libraryService.getComputeLibGroups()).build();
+    }
+
+    /**
+     * Returns list of installed/failed libraries for datalab resource <code>exploratoryName<code/>
+     * and <code>computationalName<code/> resource
+     *
+     * @param userInfo          user info
+     * @param exploratoryName   name of exploratory resource
+     * @param computationalName name of computational cluster
+     * @return list of libraries
+     */
+    @GET
+    @Path("/lib_list")
+    public List<Document> getLibList(@Auth UserInfo userInfo,
+                                     @QueryParam("project_name") @NotBlank String projectName,
+                                     @QueryParam("exploratory_name") @NotBlank String exploratoryName,
+                                     @QueryParam("computational_name") String computationalName) {
+
+        log.debug("Loading list of libraries for user {} and exploratory {} and computational {}", userInfo.getName(),
+                exploratoryName, computationalName);
+        try {
+            return libraryService.getLibs(userInfo.getName(), projectName, exploratoryName, computationalName);
+
+        } catch (Exception t) {
+            log.error("Cannot load installed libraries for user {} and exploratory {} an", userInfo.getName(),
+                    exploratoryName, t);
+            throw new DatalabException("Cannot load installed libraries: " + t.getLocalizedMessage(), t);
+        }
+    }
+
+    /**
+     * Returns formatted representation of installed libraries or libraries that were tried to be installed for
+     * exploratory
+     * and computational resources that relate to <code>exploratoryName<code/> exploratory resource with its's
+     * statuses.
+     *
+     * @param userInfo        user info.
+     * @param exploratoryName name of exploratory resource.
+     * @return list of installed/failed libraries
+     */
+    @GET
+    @Path("/lib_list/formatted")
+    public List<LibInfoRecord> getLibListFormatted(@Auth UserInfo userInfo,
+                                                   @QueryParam("project_name") @NotBlank String projectName,
+                                                   @QueryParam("exploratory_name") @NotBlank String exploratoryName) {
+
+        log.debug("Loading formatted list of libraries for user {} and exploratory {}", userInfo.getName(),
+                exploratoryName);
+        try {
+            return libraryService.getLibInfo(userInfo.getName(), projectName, exploratoryName);
+        } catch (Exception t) {
+            log.error("Cannot load list of libraries for user {} and exploratory {}", userInfo.getName(),
+                    exploratoryName, t);
+            throw new DatalabException("Cannot load  formatted list of installed libraries: " + t.getLocalizedMessage(),
+                    t);
+        }
+    }
+
+    /**
+     * Install libraries to the exploratory environment.
+     *
+     * @param userInfo user info.
+     * @param formDTO  description of libraries which will be installed to the exploratory environment.
+     * @return Invocation response as JSON string.
+     */
+    @POST
+    @Path("/lib_install")
+    public Response libInstall(@Auth UserInfo userInfo,
+                               @Valid @NotNull LibInstallFormDTO formDTO) {
+        log.debug("Installing libs to environment {} for user {}", formDTO, userInfo.getName());
+        String project = formDTO.getProject();
+        final String exploratoryName = formDTO.getNotebookName();
+        final List<LibInstallDTO> libs = formDTO.getLibs();
+        final String computationalName = formDTO.getComputationalName();
+        final String auditInfo = getAuditInfo(libs);
+        String uuid = StringUtils.isEmpty(computationalName) ?
+                libraryService.installExploratoryLibs(userInfo, project, exploratoryName, libs, auditInfo) :
+                libraryService.installComputationalLibs(userInfo, project, exploratoryName, computationalName, libs, auditInfo);
+        return Response.ok(uuid)
+                .build();
+    }
+
+    /**
+     * Returns the list of available libraries for exploratory basing on search conditions provided in @searchDTO.
+     *
+     * @param userInfo  user info.
+     * @param searchDTO search condition for find libraries for the exploratory environment.
+     * @return found libraries
+     */
+    @POST
+    @Path("search/lib_list")
+    public Response getLibList(@Auth UserInfo userInfo,
+                               @Valid @NotNull SearchLibsFormDTO searchDTO) {
+        try {
+            UserInstanceDTO userInstance;
+            if (StringUtils.isNotEmpty(searchDTO.getComputationalName())) {
+                userInstance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), searchDTO.getProjectName(),
+                        searchDTO.getNotebookName(), searchDTO.getComputationalName());
+                userInstance.setResources(userInstance.getResources().stream()
+                        .filter(e -> e.getComputationalName().equals(searchDTO.getComputationalName()))
+                        .collect(Collectors.toList()));
+            } else {
+                userInstance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), searchDTO.getProjectName(), searchDTO.getNotebookName());
+            }
+
+            LibraryAutoCompleteDTO autoCompleteDTO = ExploratoryLibCache.getCache().getLibList(userInfo, userInstance, searchDTO.getGroup(), searchDTO.getStartWith());
+            return Response.ok(autoCompleteDTO).build();
+        } catch (Exception e) {
+            log.error("Cannot search libs for user {} with condition {}", userInfo.getName(), searchDTO, e);
+            throw new DatalabException("Cannot search libraries: " + e.getLocalizedMessage(), e);
+        }
+    }
+
+
+    @GET
+    @Path("search/lib_list/maven")
+    public Response getMavenArtifactInfo(@Auth UserInfo userInfo,
+                                         @LibNameValid @QueryParam("artifact") String artifact) {
+        final String[] libNameParts = artifact.split(":");
+        return Response.ok(externalLibraryService.getLibrary(libNameParts[0], libNameParts[1], libNameParts[2])).build();
+    }
+
+    private String getAuditInfo(List<LibInstallDTO> libs) {
+        return String.format(AUDIT_MESSAGE, libs
+                .stream()
+                .map(LibInstallDTO::getName)
+                .collect(Collectors.joining(", ")));
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ProjectResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ProjectResource.java
new file mode 100644
index 0000000..9ff6ee0
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ProjectResource.java
@@ -0,0 +1,244 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.BudgetDTO;
+import com.epam.datalab.backendapi.domain.CreateProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectEndpointDTO;
+import com.epam.datalab.backendapi.domain.UpdateProjectBudgetDTO;
+import com.epam.datalab.backendapi.domain.UpdateProjectDTO;
+import com.epam.datalab.backendapi.resources.dto.ProjectActionFormDTO;
+import com.epam.datalab.backendapi.service.AccessKeyService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.rest.dto.ErrorDTO;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.headers.Header;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+import javax.annotation.security.RolesAllowed;
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.net.URI;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Path("project")
+public class ProjectResource {
+    private final ProjectService projectService;
+    private final AccessKeyService keyService;
+    @Context
+    private UriInfo uriInfo;
+
+    @Inject
+    public ProjectResource(ProjectService projectService, AccessKeyService keyService) {
+        this.projectService = projectService;
+        this.keyService = keyService;
+    }
+
+
+    @Operation(summary = "Create project", tags = "project")
+    @ApiResponse(responseCode = "201", description = "Project is successfully created",
+            headers =
+            @Header(required = true, name = "Location", description = "URI of created project resource",
+                    schema = @Schema(type = "string")))
+    @ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
+            MediaType.APPLICATION_JSON,
+            schema = @Schema(implementation = ErrorDTO.class)))
+    @ApiResponse(responseCode = "409", description = "Project with passed name already exist in system",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON,
+                    schema = @Schema(implementation = ErrorDTO.class)))
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @RolesAllowed("/api/project/create")
+    public Response createProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
+                                  @Valid CreateProjectDTO projectDTO) {
+        List<ProjectEndpointDTO> projectEndpointDTOS = projectDTO.getEndpoints()
+                .stream()
+                .map(e -> new ProjectEndpointDTO(e, UserInstanceStatus.CREATING, null))
+                .collect(Collectors.toList());
+        ProjectDTO project = new ProjectDTO(projectDTO.getName(), projectDTO.getGroups(), projectDTO.getKey(), projectDTO.getTag(),
+                new BudgetDTO(), projectEndpointDTOS, projectDTO.isSharedImageEnabled());
+        projectService.create(userInfo, project, projectDTO.getName());
+        final URI uri = uriInfo.getRequestUriBuilder().path(projectDTO.getName()).build();
+        return Response
+                .ok()
+                .location(uri)
+                .build();
+    }
+
+    @Operation(summary = "Start project", tags = "project")
+    @ApiResponse(responseCode = "202", description = "Project is starting")
+    @ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
+            MediaType.APPLICATION_JSON,
+            schema = @Schema(implementation = ErrorDTO.class)))
+    @Path("start")
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @RolesAllowed("/api/project")
+    public Response startProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
+                                 @NotNull @Valid ProjectActionFormDTO startProjectDto) {
+        projectService.start(userInfo, startProjectDto.getEndpoints(), startProjectDto.getProjectName());
+        return Response
+                .accepted()
+                .build();
+    }
+
+    @Operation(summary = "Stop project", tags = "project")
+    @ApiResponse(responseCode = "202", description = "Project is stopping")
+    @ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
+            MediaType.APPLICATION_JSON,
+            schema = @Schema(implementation = ErrorDTO.class)))
+    @Path("stop")
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @RolesAllowed("/api/project")
+    public Response stopProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
+                                @NotNull @Valid ProjectActionFormDTO stopProjectDTO) {
+        projectService.stopWithResources(userInfo, stopProjectDTO.getEndpoints(), stopProjectDTO.getProjectName());
+        return Response
+                .accepted()
+                .build();
+    }
+
+    @Operation(summary = "Get project info", tags = "project")
+    @ApiResponse(responseCode = "200", description = "Return information about project",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
+            @Schema(implementation = ProjectDTO.class)))
+    @ApiResponse(responseCode = "404", description = "Project with passed name not found",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON,
+                    schema = @Schema(implementation = ErrorDTO.class)))
+    @GET
+    @Path("{name}")
+    @Produces(MediaType.APPLICATION_JSON)
+    @RolesAllowed("/api/project")
+    public Response getProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
+                               @Parameter(description = "Project name")
+                               @PathParam("name") String name) {
+        return Response
+                .ok(projectService.get(name))
+                .build();
+    }
+
+    @Operation(summary = "Get available projects", tags = "project")
+    @ApiResponse(responseCode = "200", description = "Return information about projects",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
+            @Schema(implementation = ProjectDTO.class)))
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @RolesAllowed("/api/project")
+    public Response getProjects(@Parameter(hidden = true) @Auth UserInfo userInfo) {
+        return Response
+                .ok(projectService.getProjects(userInfo))
+                .build();
+    }
+
+    @Operation(summary = "Get projects assigned to user", tags = "project")
+    @ApiResponse(responseCode = "200", description = "Return information about projects",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
+            @Schema(implementation = ProjectDTO.class)))
+    @GET
+    @Path("/me")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getUserProjects(@Parameter(hidden = true) @Auth UserInfo userInfo,
+                                    @QueryParam("active") @DefaultValue("false") boolean active) {
+        return Response
+                .ok(projectService.getUserProjects(userInfo, active))
+                .build();
+    }
+
+    @Operation(summary = "Update project", tags = "project")
+    @ApiResponse(responseCode = "200", description = "Project is successfully updated")
+    @ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
+            MediaType.APPLICATION_JSON,
+            schema = @Schema(implementation = ErrorDTO.class)))
+    @ApiResponse(responseCode = "404", description = "Project with passed name not found",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON,
+                    schema = @Schema(implementation = ErrorDTO.class)))
+    @PUT
+    @RolesAllowed("/api/project")
+    public Response updateProject(@Parameter(hidden = true) @Auth UserInfo userInfo, UpdateProjectDTO projectDTO) {
+        projectService.update(userInfo, projectDTO, projectDTO.getName());
+        return Response.ok().build();
+    }
+
+    @Operation(summary = "Remove project", tags = "project")
+    @ApiResponse(responseCode = "200", description = "Project is successfully removed")
+    @ApiResponse(responseCode = "404", description = "Project with passed name not found",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON,
+                    schema = @Schema(implementation = ErrorDTO.class)))
+    @POST
+    @Path("terminate")
+    @RolesAllowed("/api/project")
+    public Response removeProjectEndpoint(@Parameter(hidden = true) @Auth UserInfo userInfo,
+                                          @NotNull @Valid ProjectActionFormDTO projectActionDTO) {
+        projectService.terminateEndpoint(userInfo, projectActionDTO.getEndpoints(), projectActionDTO.getProjectName());
+        return Response.ok().build();
+    }
+
+    @Operation(summary = "Updates project budget", tags = "project")
+    @ApiResponse(responseCode = "200", description = "Project budget is successfully updated")
+    @ApiResponse(responseCode = "404", description = "Project with specified name not found")
+    @ApiResponse(responseCode = "400", description = "Validation error",
+            content = @Content(mediaType = MediaType.APPLICATION_JSON,
+                    schema = @Schema(implementation = ErrorDTO.class)))
+    @PUT
+    @Path("/budget")
+    @RolesAllowed("/api/project")
+    public Response updateBudget(
+            @Parameter(hidden = true) @Auth UserInfo userInfo,
+            @Parameter(description = "Update project budgets list") List<UpdateProjectBudgetDTO> dtos) {
+        projectService.updateBudget(userInfo, dtos);
+        return Response.ok().build();
+    }
+
+    @Operation(summary = "Generate keys for project", tags = "project")
+    @ApiResponse(responseCode = "200", description = "Keys are successfully generated")
+    @POST
+    @Path("/keys")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @RolesAllowed("/api/project")
+    public Response generate(@Parameter(hidden = true) @Auth UserInfo userInfo) {
+        return Response
+                .ok(keyService.generateKeys(userInfo))
+                .build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/SchedulerJobResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/SchedulerJobResource.java
new file mode 100644
index 0000000..d2e3e4c
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/SchedulerJobResource.java
@@ -0,0 +1,187 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.SchedulerJobService;
+import com.epam.datalab.backendapi.validation.annotation.SchedulerJobDTOValid;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Manages scheduler jobs for exploratory environment
+ */
+@Path("/infrastructure_provision/exploratory_environment/scheduler")
+@Slf4j
+public class SchedulerJobResource {
+
+    private SchedulerJobService schedulerJobService;
+
+    @Inject
+    public SchedulerJobResource(SchedulerJobService schedulerJobService) {
+        this.schedulerJobService = schedulerJobService;
+    }
+
+
+    /**
+     * Updates exploratory <code>exploratoryName<code/> for user <code>userInfo<code/> with new scheduler job data
+     *
+     * @param userInfo        user info
+     * @param exploratoryName name of exploratory resource
+     * @param dto             scheduler job data
+     * @return response
+     */
+    @POST
+    @Path("/{projectName}/{exploratoryName}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response updateExploratoryScheduler(@Auth UserInfo userInfo,
+                                               @PathParam("projectName") String projectName,
+                                               @PathParam("exploratoryName") String exploratoryName,
+                                               @SchedulerJobDTOValid SchedulerJobDTO dto) {
+        schedulerJobService.updateExploratorySchedulerData(userInfo, projectName, exploratoryName, dto);
+        return Response.ok().build();
+    }
+
+    /**
+     * Removes exploratory <code>exploratoryName<code/> for user <code>userInfo<code/>
+     *
+     * @param userInfo        user info
+     * @param exploratoryName name of exploratory resource
+     * @return response
+     */
+    @DELETE
+    @Path("/{exploratoryName}")
+    public Response removeExploratoryScheduler(@Auth UserInfo userInfo,
+                                               @PathParam("exploratoryName") String exploratoryName) {
+        log.debug("User {} is trying to remove scheduler for exploratory {}", userInfo.getName(), exploratoryName);
+        schedulerJobService.removeScheduler(userInfo.getName(), exploratoryName);
+        return Response.ok().build();
+    }
+
+    /**
+     * Updates computational resource <code>computationalName<code/> affiliated with exploratory
+     * <code>exploratoryName<code/> for user <code>userInfo<code/> with new scheduler job data
+     *
+     * @param userInfo          user info
+     * @param exploratoryName   name of exploratory resource
+     * @param computationalName name of computational resource
+     * @param dto               scheduler job data
+     * @return response
+     */
+    @POST
+    @Path("/{projectName}/{exploratoryName}/{computationalName}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response updateComputationalScheduler(@Auth UserInfo userInfo,
+                                                 @PathParam("projectName") String projectName,
+                                                 @PathParam("exploratoryName") String exploratoryName,
+                                                 @PathParam("computationalName") String computationalName,
+                                                 @SchedulerJobDTOValid SchedulerJobDTO dto) {
+        schedulerJobService.updateComputationalSchedulerData(userInfo, projectName, exploratoryName, computationalName, dto);
+        return Response.ok().build();
+    }
+
+    /**
+     * Updates computational resource <code>computationalName<code/> affiliated with exploratory
+     * <code>exploratoryName<code/> for user <code>userInfo<code/> with new scheduler job data
+     *
+     * @param userInfo          user info
+     * @param exploratoryName   name of exploratory resource
+     * @param computationalName name of computational resource
+     * @return response
+     */
+    @DELETE
+    @Path("/{exploratoryName}/{computationalName}")
+    public Response removeComputationalScheduler(@Auth UserInfo userInfo,
+                                                 @PathParam("exploratoryName") String exploratoryName,
+                                                 @PathParam("computationalName") String computationalName) {
+        log.debug("User {} is trying to remove scheduler for computational {} connected with exploratory {}",
+                userInfo.getName(), computationalName, exploratoryName);
+        schedulerJobService.removeScheduler(userInfo.getName(), exploratoryName, computationalName);
+        return Response.ok().build();
+    }
+
+
+    /**
+     * Returns scheduler job for exploratory resource <code>exploratoryName<code/>
+     *
+     * @param userInfo        user info
+     * @param exploratoryName name of exploratory resource
+     * @return scheduler job data
+     */
+    @GET
+    @Path("/{projectName}/{exploratoryName}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response fetchSchedulerJobForUserAndExploratory(@Auth UserInfo userInfo,
+                                                           @PathParam("projectName") String projectName,
+                                                           @PathParam("exploratoryName") String exploratoryName) {
+        log.debug("Loading scheduler job for user {} and exploratory {}...", userInfo.getName(), exploratoryName);
+        final SchedulerJobDTO schedulerJob =
+                schedulerJobService.fetchSchedulerJobForUserAndExploratory(userInfo.getName(), projectName, exploratoryName);
+        return Response.ok(schedulerJob).build();
+    }
+
+    /**
+     * Returns scheduler job for computational resource <code>computationalName<code/> affiliated with
+     * exploratory <code>exploratoryName<code/>
+     *
+     * @param userInfo          user info
+     * @param exploratoryName   name of exploratory resource
+     * @param computationalName name of computational resource
+     * @return scheduler job data
+     */
+    @GET
+    @Path("/{projectName}/{exploratoryName}/{computationalName}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response fetchSchedulerJobForComputationalResource(@Auth UserInfo userInfo,
+                                                              @PathParam("exploratoryName") String exploratoryName,
+                                                              @PathParam("projectName") String projectName,
+                                                              @PathParam("computationalName") String computationalName) {
+        log.debug("Loading scheduler job for user {}, exploratory {} and computational resource {}...",
+                userInfo.getName(), exploratoryName, computationalName);
+        final SchedulerJobDTO schedulerJob = schedulerJobService
+                .fetchSchedulerJobForComputationalResource(userInfo.getName(), projectName, exploratoryName, computationalName);
+        return Response.ok(schedulerJob).build();
+    }
+
+    @GET
+    @Path("active")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getActiveSchedulers(@Auth UserInfo userInfo,
+                                        @QueryParam("minuteOffset") long minuteOffset) {
+        log.trace("Getting active schedulers for user {} and offset {}", userInfo.getName(), minuteOffset);
+        return Response.ok(schedulerJobService.getActiveSchedulers(userInfo.getName(), minuteOffset)).build();
+    }
+
+}
+
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/SystemInfoResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/SystemInfoResource.java
new file mode 100644
index 0000000..c8ac3e3
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/SystemInfoResource.java
@@ -0,0 +1,56 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.SystemInfoDto;
+import com.epam.datalab.backendapi.service.SystemInfoService;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Slf4j
+@Path("sysinfo")
+@Produces(MediaType.APPLICATION_JSON)
+@RolesAllowed("sysinfo")
+public class SystemInfoResource {
+
+    private SystemInfoService systemInfoService;
+
+    @Inject
+    public SystemInfoResource(SystemInfoService systemInfoService) {
+        this.systemInfoService = systemInfoService;
+    }
+
+
+    @GET
+
+    public Response getSystemInfo(@Auth UserInfo userInfo) {
+        log.debug("Getting system info for user {}...", userInfo.getName());
+        final SystemInfoDto systemInfoDto = systemInfoService.getSystemInfo();
+        return Response.ok(systemInfoDto).build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/UserGroupResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/UserGroupResource.java
new file mode 100644
index 0000000..b8d92b6
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/UserGroupResource.java
@@ -0,0 +1,87 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.GroupDTO;
+import com.epam.datalab.backendapi.resources.dto.UpdateGroupDTO;
+import com.epam.datalab.backendapi.service.UserGroupService;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.annotation.security.RolesAllowed;
+import javax.validation.Valid;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Slf4j
+@Path("group")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class UserGroupResource {
+
+    private final UserGroupService userGroupService;
+
+    @Inject
+    public UserGroupResource(UserGroupService userGroupService) {
+        this.userGroupService = userGroupService;
+    }
+
+
+    @POST
+    @RolesAllowed("/roleManagement/create")
+    public Response createGroup(@Auth UserInfo userInfo, @Valid GroupDTO dto) {
+        log.debug("Creating new group {}", dto.getName());
+        userGroupService.createGroup(userInfo, dto.getName(), dto.getRoleIds().keySet(), dto.getUsers());
+        return Response.ok().build();
+    }
+
+    @PUT
+    @RolesAllowed("/roleManagement")
+    public Response updateGroup(@Auth UserInfo userInfo, @Valid UpdateGroupDTO dto) {
+        log.debug("Updating group {}", dto.getName());
+        userGroupService.updateGroup(userInfo, dto.getName(), dto.getRoles(), dto.getUsers());
+        return Response.ok().build();
+    }
+
+    @GET
+    @RolesAllowed("/roleManagement")
+    public Response getGroups(@Auth UserInfo userInfo) {
+        log.debug("Getting all groups for admin {}...", userInfo.getName());
+        return Response.ok(userGroupService.getAggregatedRolesByGroup(userInfo)).build();
+    }
+
+    @DELETE
+    @Path("{id}")
+    @RolesAllowed("/roleManagement/delete")
+    public Response deleteGroup(@Auth UserInfo userInfo, @PathParam("id") String group) {
+        log.info("Admin {} is trying to delete group {} from application", userInfo.getName(), group);
+        userGroupService.removeGroup(userInfo, group);
+        return Response.ok().build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/UserRoleResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/UserRoleResource.java
new file mode 100644
index 0000000..10e0ca6
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/UserRoleResource.java
@@ -0,0 +1,63 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.UserRoleDto;
+import com.epam.datalab.backendapi.service.UserRoleService;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.annotation.security.RolesAllowed;
+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;
+
+@Slf4j
+@Path("role")
+@RolesAllowed("/roleManagement")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class UserRoleResource {
+
+    private final UserRoleService userRoleService;
+
+    @Inject
+    public UserRoleResource(UserRoleService roleService) {
+        this.userRoleService = roleService;
+    }
+
+    @GET
+    public Response getRoles(@Auth UserInfo userInfo) {
+        log.debug("Getting all roles for admin {}...", userInfo.getName());
+        return Response.ok(userRoleService.getUserRoles()).build();
+    }
+
+    @POST
+    public Response createRole(@Auth UserInfo userInfo, UserRoleDto dto) {
+        log.info("Creating new role {} on behalf of admin {}...", dto, userInfo.getName());
+        userRoleService.createRole(dto);
+        return Response.ok().build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/UserSettingsResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/UserSettingsResource.java
new file mode 100644
index 0000000..b380c3b
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/UserSettingsResource.java
@@ -0,0 +1,84 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.UserDTO;
+import com.epam.datalab.backendapi.service.UserSettingService;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import org.hibernate.validator.constraints.NotBlank;
+import org.hibernate.validator.constraints.NotEmpty;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.security.RolesAllowed;
+import javax.validation.Valid;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+
+@Path("/user/settings")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class UserSettingsResource {
+	private static final Logger LOGGER = LoggerFactory.getLogger(UserSettingsResource.class);
+
+	private UserSettingService userSettingService;
+
+	@Inject
+	public UserSettingsResource(UserSettingService userSettingService) {
+		this.userSettingService = userSettingService;
+	}
+
+	@GET
+	public String getSettings(@Auth UserInfo userInfo) {
+		String settings = userSettingService.getUISettings(userInfo);
+		LOGGER.debug("Returns settings for user {}, content is {}", userInfo.getName(), settings);
+		return settings;
+	}
+
+	@POST
+	public Response saveSettings(@Auth UserInfo userInfo,
+								 @NotBlank String settings) {
+		LOGGER.debug("Saves settings for user {}, content is {}", userInfo.getName(), settings);
+		userSettingService.saveUISettings(userInfo, settings);
+		return Response.ok().build();
+	}
+
+	@PUT
+	@Path("budget")
+	@RolesAllowed("/user/settings")
+	public Response updateUsersBudget(@Auth UserInfo userInfo,
+									  @Valid @NotEmpty List<UserDTO> budgets) {
+		LOGGER.debug("User {} is updating allowed budget for users: {}", userInfo.getName(), budgets);
+		userSettingService.updateUsersBudget(budgets);
+		return Response.ok().build();
+	}
+
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/aws/ComputationalResourceAws.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/aws/ComputationalResourceAws.java
new file mode 100644
index 0000000..7d98260
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/aws/ComputationalResourceAws.java
@@ -0,0 +1,272 @@
+/*
+ * 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.datalab.backendapi.resources.aws;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
+import com.epam.datalab.backendapi.resources.dto.aws.AwsComputationalCreateForm;
+import com.epam.datalab.backendapi.roles.RoleType;
+import com.epam.datalab.backendapi.roles.UserRoles;
+import com.epam.datalab.backendapi.service.ComputationalService;
+import com.epam.datalab.dto.aws.computational.AwsComputationalResource;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.contracts.ComputationalAPI;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import io.swagger.v3.oas.annotations.Parameter;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+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.List;
+
+import static com.epam.datalab.dto.UserInstanceStatus.CREATING;
+import static com.epam.datalab.dto.base.DataEngineType.SPARK_STANDALONE;
+
+
+/**
+ * Provides the REST API for the computational resource on AWS.
+ */
+@Path("/aws/infrastructure_provision/computational_resources")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ComputationalResourceAws implements ComputationalAPI {
+    @Inject
+    private SelfServiceApplicationConfiguration configuration;
+    @Inject
+    private ComputationalService computationalService;
+
+    @GET
+    @Path("/{project}/{endpoint}/templates")
+    public Response getTemplates(@Auth @Parameter(hidden = true) UserInfo userInfo, @PathParam("project") String project,
+                                 @PathParam("endpoint") String endpoint) {
+        return Response.ok(computationalService.getComputationalNamesAndTemplates(userInfo, project, endpoint)).build();
+    }
+
+    /**
+     * Asynchronously creates EMR cluster
+     *
+     * @param userInfo user info.
+     * @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
+     */
+    @PUT
+    @Path("dataengine-service")
+    public Response createDataEngineService(@Auth @Parameter(hidden = true) UserInfo userInfo,
+                                            @Parameter @Valid @NotNull AwsComputationalCreateForm form) {
+
+        log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
+
+        if (DataEngineType.CLOUD_SERVICE == DataEngineType.fromDockerImageName(form.getImage())) {
+
+            validate(userInfo, form);
+
+            AwsComputationalResource awsComputationalResource = AwsComputationalResource.builder()
+                    .computationalName(form.getName())
+                    .imageName(form.getImage())
+                    .templateName(form.getTemplateName())
+                    .status(CREATING.toString())
+                    .masterShape(form.getMasterInstanceType())
+                    .slaveShape(form.getSlaveInstanceType())
+                    .slaveSpot(form.getSlaveInstanceSpot())
+                    .slaveSpotPctPrice(form.getSlaveInstanceSpotPctPrice())
+                    .slaveNumber(form.getInstanceCount())
+                    .config(form.getConfig())
+                    .version(form.getVersion())
+                    .totalInstanceCount(Integer.parseInt(form.getInstanceCount()))
+                    .build();
+            boolean resourceAdded = computationalService.createDataEngineService(userInfo, form.getName(), form, awsComputationalResource,
+                    form.getProject(), getAuditInfo(form.getNotebookName()));
+            return resourceAdded ? Response.ok().build() : Response.status(Response.Status.FOUND).build();
+        }
+
+        throw new IllegalArgumentException("Malformed image " + form.getImage());
+    }
+
+    /**
+     * Asynchronously triggers creation of Spark cluster
+     *
+     * @param userInfo user info.
+     * @param form     DTO info about creation of the computational resource.
+     * @return 200 OK - if request success, 302 Found - for duplicates.
+     */
+
+    @PUT
+    @Path("dataengine")
+    public Response createDataEngine(@Auth UserInfo userInfo,
+                                     @Valid @NotNull SparkStandaloneClusterCreateForm form) {
+        log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
+
+        validate(form);
+        return computationalService.createSparkCluster(userInfo, form.getName(), form, form.getProject(), getAuditInfo(form.getNotebookName()))
+                ? Response.ok().build()
+                : Response.status(Response.Status.FOUND).build();
+    }
+
+    /**
+     * Sends request to provisioning service for termination the computational resource for user.
+     *
+     * @param userInfo          user info.
+     * @param exploratoryName   name of exploratory.
+     * @param computationalName name of computational resource.
+     * @return 200 OK if operation is successfully triggered
+     */
+    @DELETE
+    @Path("/{projectName}/{exploratoryName}/{computationalName}/terminate")
+    public Response terminate(@Auth UserInfo userInfo,
+                              @PathParam("projectName") String projectName,
+                              @PathParam("exploratoryName") String exploratoryName,
+                              @PathParam("computationalName") String computationalName) {
+        log.debug("Terminating computational resource {} for user {}", computationalName, userInfo.getName());
+
+        computationalService.terminateComputational(userInfo, userInfo.getName(), projectName, exploratoryName, computationalName, getAuditInfo(exploratoryName));
+
+        return Response.ok().build();
+    }
+
+    /**
+     * Sends request to provisioning service for stopping the computational resource for user.
+     *
+     * @param userInfo          user info.
+     * @param exploratoryName   name of exploratory.
+     * @param computationalName name of computational resource.
+     * @return 200 OK if operation is successfully triggered
+     */
+    @DELETE
+    @Path("/{project}/{exploratoryName}/{computationalName}/stop")
+    public Response stop(@Auth UserInfo userInfo,
+                         @PathParam("project") String project,
+                         @PathParam("exploratoryName") String exploratoryName,
+                         @PathParam("computationalName") String computationalName) {
+        log.debug("Stopping computational resource {} for user {}", computationalName, userInfo.getName());
+
+        computationalService.stopSparkCluster(userInfo, userInfo.getName(), project, exploratoryName, computationalName, getAuditInfo(exploratoryName));
+        return Response.ok().build();
+    }
+
+    /**
+     * Sends request to provisioning service for starting the computational resource for user.
+     *
+     * @param userInfo          user info.
+     * @param exploratoryName   name of exploratory.
+     * @param computationalName name of computational resource.
+     * @return 200 OK if operation is successfully triggered
+     */
+    @PUT
+    @Path("/{project}/{exploratoryName}/{computationalName}/start")
+    public Response start(@Auth UserInfo userInfo,
+                          @PathParam("exploratoryName") String exploratoryName,
+                          @PathParam("computationalName") String computationalName,
+                          @PathParam("project") String project) {
+        log.debug("Starting computational resource {} for user {}", computationalName, userInfo.getName());
+
+        computationalService.startSparkCluster(userInfo, exploratoryName, computationalName, project, getAuditInfo(exploratoryName));
+        return Response.ok().build();
+    }
+
+    @PUT
+    @Path("dataengine/{projectName}/{exploratoryName}/{computationalName}/config")
+    public Response updateDataEngineConfig(@Auth UserInfo userInfo,
+                                           @PathParam("projectName") String projectName,
+                                           @PathParam("exploratoryName") String exploratoryName,
+                                           @PathParam("computationalName") String computationalName,
+                                           @Valid @NotNull List<ClusterConfig> config) {
+        computationalService.updateSparkClusterConfig(userInfo, projectName, exploratoryName, computationalName, config,
+                String.format(AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE, computationalName, exploratoryName));
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/{projectName}/{exploratoryName}/{computationalName}/config")
+    public Response getClusterConfig(@Auth UserInfo userInfo,
+                                     @PathParam("projectName") String projectName,
+                                     @PathParam("exploratoryName") String exploratoryName,
+                                     @PathParam("computationalName") String computationalName) {
+        return Response.ok(computationalService.getClusterConfig(userInfo, projectName, exploratoryName, computationalName)).build();
+    }
+
+    private void validate(SparkStandaloneClusterCreateForm form) {
+
+        int instanceCount = Integer.parseInt(form.getDataEngineInstanceCount());
+
+        if (instanceCount < configuration.getMinSparkInstanceCount()
+                || instanceCount > configuration.getMaxSparkInstanceCount()) {
+            throw new IllegalArgumentException(String.format("Instance count should be in range [%d..%d]",
+                    configuration.getMinSparkInstanceCount(), configuration.getMaxSparkInstanceCount()));
+        }
+
+        if (DataEngineType.fromDockerImageName(form.getImage()) != SPARK_STANDALONE) {
+            throw new IllegalArgumentException(String.format("Unknown data engine %s", form.getImage()));
+        }
+    }
+
+    private void validate(UserInfo userInfo, AwsComputationalCreateForm formDTO) {
+        if (!UserRoles.checkAccess(userInfo, RoleType.COMPUTATIONAL, formDTO.getImage(), userInfo.getRoles())) {
+            log.warn("Unauthorized attempt to create a {} by user {}", formDTO.getImage(), userInfo.getName());
+            throw new DatalabException("You do not have the privileges to create a " + formDTO.getTemplateName());
+        }
+
+        int slaveInstanceCount = Integer.parseInt(formDTO.getInstanceCount());
+        if (slaveInstanceCount < configuration.getMinEmrInstanceCount() || slaveInstanceCount >
+                configuration.getMaxEmrInstanceCount()) {
+            log.debug("Creating computational resource {} for user {} fail: Limit exceeded to creation slave " +
+                            "instances. Minimum is {}, maximum is {}",
+                    formDTO.getName(), userInfo.getName(), configuration.getMinEmrInstanceCount(),
+                    configuration.getMaxEmrInstanceCount());
+            throw new DatalabException("Limit exceeded to creation slave instances. Minimum is " +
+                    configuration.getMinEmrInstanceCount() + ", maximum is " + configuration.getMaxEmrInstanceCount() +
+                    ".");
+        }
+
+        if (formDTO.getSlaveInstanceSpotPctPrice() != null) {
+            int slaveSpotInstanceBidPct = formDTO.getSlaveInstanceSpotPctPrice();
+            if (formDTO.getSlaveInstanceSpot() && (slaveSpotInstanceBidPct < configuration.getMinEmrSpotInstanceBidPct()
+                    || slaveSpotInstanceBidPct > configuration.getMaxEmrSpotInstanceBidPct())) {
+                log.debug("Creating computational resource {} for user {} fail: Spot instances bidding percentage " +
+                                "value " +
+                                "out of the boundaries. Minimum is {}, maximum is {}",
+                        formDTO.getName(), userInfo.getName(), configuration.getMinEmrSpotInstanceBidPct(),
+                        configuration.getMaxEmrSpotInstanceBidPct());
+                throw new DatalabException("Spot instances bidding percentage value out of the boundaries. Minimum is " +
+                        configuration.getMinEmrSpotInstanceBidPct() + ", maximum is " +
+                        configuration.getMaxEmrSpotInstanceBidPct() + ".");
+            }
+        }
+    }
+
+    private String getAuditInfo(String exploratoryName) {
+        return String.format(AUDIT_MESSAGE, exploratoryName);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/azure/AzureOauthResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/azure/AzureOauthResource.java
new file mode 100644
index 0000000..764d432
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/azure/AzureOauthResource.java
@@ -0,0 +1,60 @@
+/*
+ * 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.datalab.backendapi.resources.azure;
+
+import com.epam.datalab.auth.contract.SecurityAPI;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.azure.auth.AuthorizationCodeFlowResponse;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
+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;
+import java.net.URI;
+
+@Path("/user/azure")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class AzureOauthResource {
+
+	@Inject
+	@Named(ServiceConsts.SECURITY_SERVICE_NAME)
+	private RESTService securityService;
+
+
+	@GET
+	@Path("/init")
+	public Response redirectedUrl() {
+		return Response.seeOther(URI.create(securityService.get(SecurityAPI.INIT_LOGIN_OAUTH_AZURE, String.class)))
+				.build();
+	}
+
+	@POST
+	@Path("/oauth")
+	public Response login(AuthorizationCodeFlowResponse codeFlowResponse) {
+		return securityService.post(SecurityAPI.LOGIN_OAUTH_AZURE, codeFlowResponse, Response.class);
+	}
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java
new file mode 100644
index 0000000..7b7f282
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java
@@ -0,0 +1,181 @@
+/*
+ * 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.datalab.backendapi.resources.azure;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
+import com.epam.datalab.backendapi.roles.RoleType;
+import com.epam.datalab.backendapi.roles.UserRoles;
+import com.epam.datalab.backendapi.service.ComputationalService;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import io.swagger.v3.oas.annotations.Parameter;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+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.List;
+
+import static com.epam.datalab.rest.contracts.ComputationalAPI.AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE;
+import static com.epam.datalab.rest.contracts.ComputationalAPI.AUDIT_MESSAGE;
+
+/**
+ * Provides the REST API for the computational resource on Azure.
+ */
+@Path("/azure/infrastructure_provision/computational_resources")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ComputationalResourceAzure {
+	private final ComputationalService computationalService;
+
+	@Inject
+	public ComputationalResourceAzure(ComputationalService computationalService) {
+		this.computationalService = computationalService;
+	}
+
+	@GET
+	@Path("/{project}/{endpoint}/templates")
+	public Response getTemplates(@Auth @Parameter(hidden = true) UserInfo userInfo, @PathParam("project") String project,
+								 @PathParam("endpoint") String endpoint) {
+		return Response.ok(computationalService.getComputationalNamesAndTemplates(userInfo, project, endpoint)).build();
+	}
+
+	/**
+	 * Asynchronously creates computational Spark cluster.
+	 *
+	 * @param userInfo user info.
+	 * @param form     user info about creation of the computational resource.
+	 * @return 200 OK if request success, 302 Found - for duplicates, otherwise throws exception.
+	 * @throws IllegalArgumentException if input is not valid or exceeds configuration limits
+	 */
+	@PUT
+	@Path("dataengine")
+	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 DatalabException("You do not have the privileges to create a " + form.getTemplateName());
+		}
+
+		return computationalService.createSparkCluster(userInfo, form.getName(), form, form.getProject(), getAuditInfo(form.getNotebookName()))
+				? Response.ok().build()
+				: Response.status(Response.Status.FOUND).build();
+	}
+
+	/**
+	 * Sends request to provisioning service for termination the computational resource for user.
+	 *
+	 * @param userInfo          user info.
+	 * @param exploratoryName   name of exploratory.
+	 * @param computationalName name of computational resource.
+	 * @return 200 OK if operation is successfully triggered
+	 */
+	@DELETE
+	@Path("/{projectName}/{exploratoryName}/{computationalName}/terminate")
+	public Response terminate(@Auth UserInfo userInfo,
+							  @PathParam("projectName") String projectName,
+							  @PathParam("exploratoryName") String exploratoryName,
+							  @PathParam("computationalName") String computationalName) {
+
+		log.debug("Terminating computational resource {} for user {}", computationalName, userInfo.getName());
+
+		computationalService.terminateComputational(userInfo, userInfo.getName(), projectName, exploratoryName, computationalName, getAuditInfo(exploratoryName));
+		return Response.ok().build();
+	}
+
+	/**
+	 * Sends request to provisioning service for stopping the computational resource for user.
+	 *
+	 * @param userInfo          user info.
+	 * @param exploratoryName   name of exploratory.
+	 * @param computationalName name of computational resource.
+	 * @return 200 OK if operation is successfully triggered
+	 */
+	@DELETE
+	@Path("/{project}/{exploratoryName}/{computationalName}/stop")
+	public Response stop(@Auth UserInfo userInfo,
+						 @PathParam("project") String project,
+						 @PathParam("exploratoryName") String exploratoryName,
+						 @PathParam("computationalName") String computationalName) {
+		log.debug("Stopping computational resource {} for user {}", computationalName, userInfo.getName());
+
+		computationalService.stopSparkCluster(userInfo, userInfo.getName(), project, exploratoryName, computationalName, getAuditInfo(exploratoryName));
+		return Response.ok().build();
+	}
+
+	/**
+	 * Sends request to provisioning service for starting the computational resource for user.
+	 *
+	 * @param userInfo          user info.
+	 * @param exploratoryName   name of exploratory.
+	 * @param computationalName name of computational resource.
+	 * @return 200 OK if operation is successfully triggered
+	 */
+	@PUT
+	@Path("/{project}/{exploratoryName}/{computationalName}/start")
+	public Response start(@Auth UserInfo userInfo,
+						  @PathParam("exploratoryName") String exploratoryName,
+						  @PathParam("computationalName") String computationalName,
+						  @PathParam("project") String project) {
+		log.debug("Starting computational resource {} for user {}", computationalName, userInfo.getName());
+
+		computationalService.startSparkCluster(userInfo, exploratoryName, computationalName, project, getAuditInfo(exploratoryName));
+		return Response.ok().build();
+	}
+
+	@PUT
+	@Path("dataengine/{projectName}/{exploratoryName}/{computationalName}/config")
+	public Response updateDataEngineConfig(@Auth UserInfo userInfo,
+										   @PathParam("projectName") String projectName,
+										   @PathParam("exploratoryName") String exploratoryName,
+										   @PathParam("computationalName") String computationalName,
+										   @Valid @NotNull List<ClusterConfig> config) {
+
+		computationalService.updateSparkClusterConfig(userInfo, projectName, exploratoryName, computationalName, config,
+				String.format(AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE, computationalName, exploratoryName));
+		return Response.ok().build();
+	}
+
+	@GET
+	@Path("/{projectName}/{exploratoryName}/{computationalName}/config")
+	public Response getClusterConfig(@Auth UserInfo userInfo,
+									 @PathParam("projectName") String projectName,
+									 @PathParam("exploratoryName") String exploratoryName,
+									 @PathParam("computationalName") String computationalName) {
+		return Response.ok(computationalService.getClusterConfig(userInfo, projectName, exploratoryName, computationalName)).build();
+	}
+
+	private String getAuditInfo(String exploratoryName) {
+		return String.format(AUDIT_MESSAGE, exploratoryName);
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/BackupCallback.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/BackupCallback.java
new file mode 100644
index 0000000..52e5fb1
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/BackupCallback.java
@@ -0,0 +1,59 @@
+/*
+ * 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.datalab.backendapi.resources.callback;
+
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.BackupService;
+import com.epam.datalab.dto.backup.EnvBackupStatusDTO;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+@Path("infrastructure/backup")
+@Consumes(MediaType.APPLICATION_JSON)
+@Slf4j
+public class BackupCallback {
+
+    @Inject
+    private BackupService backupService;
+
+    @Inject
+    private RequestId requestId;
+
+    @Context
+    private UriInfo uriInfo;
+
+    @POST
+    @Path("/status")
+    public Response status(EnvBackupStatusDTO dto) {
+        requestId.remove(dto.getRequestId());
+        log.debug("Updating status of backup status to {}", dto);
+        backupService.updateStatus(dto.getEnvBackupDTO(), dto.getUser(),
+                dto.getEnvBackupStatus().withErrorMessage(dto.getErrorMessage()));
+        return Response.created(uriInfo.getRequestUri()).build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/CheckInactivityCallback.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/CheckInactivityCallback.java
new file mode 100644
index 0000000..32b0ed8
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/CheckInactivityCallback.java
@@ -0,0 +1,69 @@
+/*
+ * 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.datalab.backendapi.resources.callback;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.InactivityService;
+import com.epam.datalab.dto.computational.CheckInactivityStatusDTO;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+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;
+import java.time.LocalDateTime;
+
+import static java.time.Instant.ofEpochSecond;
+import static java.time.ZoneId.systemDefault;
+
+@Path("/infrastructure/inactivity/callback")
+@Consumes(MediaType.APPLICATION_JSON)
+@Slf4j
+public class CheckInactivityCallback {
+
+    @Inject
+    private RequestId requestId;
+    @Inject
+    private InactivityService inactivityService;
+
+    @POST
+    @Path("exploratory")
+    public Response updateExploratoryLastActivity(CheckInactivityStatusDTO dto) {
+        requestId.checkAndRemove(dto.getRequestId());
+        inactivityService.updateLastActivityForExploratory(new UserInfo(dto.getUser(), null), dto.getExploratoryName(),
+                toLocalDateTime(dto.getLastActivityUnixTime()));
+        return Response.ok().build();
+    }
+
+    @POST
+    @Path("computational")
+    public Response updateComputationalLastActivity(CheckInactivityStatusDTO dto) {
+        requestId.checkAndRemove(dto.getRequestId());
+        inactivityService.updateLastActivityForComputational(new UserInfo(dto.getUser(), null), null,
+                dto.getExploratoryName(), dto.getComputationalName(), toLocalDateTime(dto.getLastActivityUnixTime()));
+        return Response.ok().build();
+    }
+
+    private LocalDateTime toLocalDateTime(long unixTime) {
+        return ofEpochSecond(unixTime).atZone(systemDefault()).toLocalDateTime();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ComputationalCallback.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ComputationalCallback.java
new file mode 100644
index 0000000..5e074ae
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ComputationalCallback.java
@@ -0,0 +1,96 @@
+/*
+ * 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.datalab.backendapi.resources.callback;
+
+import com.epam.datalab.backendapi.dao.ComputationalDAO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.ComputationalService;
+import com.epam.datalab.backendapi.service.ReuploadKeyService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.computational.ComputationalStatusDTO;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+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;
+import java.util.Date;
+
+@Path("/infrastructure_provision/computational_resources")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ComputationalCallback {
+
+    @Inject
+    private ComputationalDAO computationalDAO;
+    @Inject
+    private RequestId requestId;
+    @Inject
+    private SecurityService securityService;
+    @Inject
+    private ReuploadKeyService reuploadKeyService;
+    @Inject
+    private ComputationalService computationalService;
+
+    /**
+     * Updates the status of the computational resource for user.
+     *
+     * @param dto DTO info about the status of the computational resource.
+     * @return 200 OK - if request success otherwise throws exception.
+     */
+    @POST
+    @Path(ApiCallbacks.STATUS_URI)
+    public Response status(ComputationalStatusDTO dto) {
+        log.debug("Updating status for computational resource {} for user {}: {}",
+                dto.getComputationalName(), dto.getUser(), dto);
+        String uuid = dto.getRequestId();
+        requestId.checkAndRemove(uuid);
+
+        UserComputationalResource compResource = computationalService.getComputationalResource(dto.getUser(), dto.getProject(),
+                dto.getExploratoryName(), dto.getComputationalName())
+                .orElseThrow(() ->
+                        new DatalabException(String.format("Computational resource %s of exploratory environment %s of " +
+                                        "project %s for user %s doesn't exist", dto.getComputationalName(),
+                                dto.getExploratoryName(), dto.getProject(), dto.getUser())));
+        log.debug("Current status for computational resource {} of exploratory environment {} for user {} is {}",
+                dto.getComputationalName(), dto.getExploratoryName(), dto.getUser(),
+                compResource.getStatus());
+        try {
+            computationalDAO.updateComputationalFields(dto.withLastActivity(new Date()));
+        } catch (DatalabException e) {
+            log.error("Could not update status for computational resource {} for user {} to {}: {}", dto, e);
+            throw e;
+        }
+        if (UserInstanceStatus.CONFIGURING == UserInstanceStatus.of(dto.getStatus())) {
+            log.debug("Waiting for configuration of the computational resource {} for user {}",
+                    dto.getComputationalName(), dto.getUser());
+            requestId.put(dto.getUser(), uuid);
+        }
+        return Response.ok().build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/EnvironmentStatusCallback.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/EnvironmentStatusCallback.java
new file mode 100644
index 0000000..e9a8202
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/EnvironmentStatusCallback.java
@@ -0,0 +1,71 @@
+/*
+ * 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.datalab.backendapi.resources.callback;
+
+import com.epam.datalab.backendapi.dao.EnvDAO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.status.EnvStatusDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+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;
+
+@Path("/infrastructure")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class EnvironmentStatusCallback {
+
+    @Inject
+    private EnvDAO envDAO;
+    @Inject
+    private RequestId requestId;
+
+    /**
+     * Updates the status of the resources for user.
+     *
+     * @param dto DTO info about the statuses of resources.
+     * @return Always return code 200 (OK).
+     */
+    @POST
+    @Path(ApiCallbacks.STATUS_URI)
+    public Response status(EnvStatusDTO dto) {
+        log.trace("Updating the status of resources for user {}: {}", dto.getUser(), dto);
+        requestId.checkAndRemove(dto.getRequestId());
+        try {
+            if (UserInstanceStatus.FAILED == UserInstanceStatus.of(dto.getStatus())) {
+                log.warn("Request for the status of resources for user {} fails: {}", dto.getUser(), dto.getErrorMessage());
+            } else {
+                envDAO.updateEnvStatus(dto.getUser(), null, dto.getResourceList());
+            }
+        } catch (DatalabException e) {
+            log.warn("Could not update status of resources for user {}: {}", dto.getUser(), e.getLocalizedMessage(), e);
+        }
+        return Response.ok().build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ExploratoryCallback.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ExploratoryCallback.java
new file mode 100644
index 0000000..1e5f8fb
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ExploratoryCallback.java
@@ -0,0 +1,137 @@
+/*
+ * 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.datalab.backendapi.resources.callback;
+
+import com.epam.datalab.backendapi.dao.ComputationalDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.ReuploadKeyService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.exploratory.ExploratoryStatusDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+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;
+import java.util.Date;
+
+import static com.epam.datalab.dto.UserInstanceStatus.FAILED;
+import static com.epam.datalab.dto.UserInstanceStatus.STOPPED;
+import static com.epam.datalab.dto.UserInstanceStatus.STOPPING;
+import static com.epam.datalab.dto.UserInstanceStatus.TERMINATED;
+import static com.epam.datalab.dto.UserInstanceStatus.TERMINATING;
+
+
+@Path("/infrastructure_provision/exploratory_environment")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ExploratoryCallback {
+
+    private static final String USER_INSTANCE_NOT_EXIST_MSG = "User instance with exploratory name %s for user %s " +
+            "doesn't exist";
+    @Inject
+    private ExploratoryDAO exploratoryDAO;
+    @Inject
+    private ComputationalDAO computationalDAO;
+    @Inject
+    private RequestId requestId;
+    @Inject
+    private SecurityService securityService;
+    @Inject
+    private ReuploadKeyService reuploadKeyService;
+    @Inject
+    private ExploratoryService exploratoryService;
+
+    /**
+     * Changes the status of exploratory environment.
+     *
+     * @param dto description of status.
+     * @return 200 OK - if request success.
+     */
+    @POST
+    @Path(ApiCallbacks.STATUS_URI)
+    public Response status(ExploratoryStatusDTO dto) {
+        log.debug("Updating status for exploratory environment {} for user {} to {}",
+                dto.getExploratoryName(), dto.getUser(), dto.getStatus());
+        requestId.checkAndRemove(dto.getRequestId());
+
+        UserInstanceDTO instance = exploratoryService.getUserInstance(dto.getUser(), dto.getProject(), dto.getExploratoryName())
+                .orElseThrow(() -> new DatalabException(String.format(USER_INSTANCE_NOT_EXIST_MSG,
+                        dto.getExploratoryName(), dto.getUser())));
+
+        UserInstanceStatus currentStatus = UserInstanceStatus.of(instance.getStatus());
+        log.debug("Current status for exploratory environment {} for user {} is {}",
+                dto.getExploratoryName(), dto.getUser(), currentStatus);
+
+        try {
+            exploratoryDAO.updateExploratoryFields(dto.withLastActivity(new Date()));
+            if (currentStatus == TERMINATING) {
+                updateComputationalStatuses(dto.getUser(), dto.getProject(), dto.getExploratoryName(),
+                        UserInstanceStatus.of(dto.getStatus()));
+            } else if (currentStatus == STOPPING) {
+                updateComputationalStatuses(dto.getUser(), dto.getProject(), dto.getExploratoryName(),
+                        UserInstanceStatus.of(dto.getStatus()), TERMINATED, FAILED, TERMINATED, STOPPED);
+            }
+        } catch (DatalabException e) {
+            log.error("Could not update status for exploratory environment {} in project {} for user {} to {}",
+                    dto.getExploratoryName(), dto.getProject(), dto.getUser(), dto.getStatus(), e);
+            throw new DatalabException("Could not update status for exploratory environment " + dto.getExploratoryName() +
+                    " for user " + dto.getUser() + " to " + dto.getStatus() + ": " + e.getLocalizedMessage(), e);
+        }
+
+        return Response.ok().build();
+    }
+
+    /**
+     * Updates the computational status of exploratory environment.
+     *
+     * @param user            user name
+     * @param project         project name
+     * @param exploratoryName name of exploratory environment.
+     * @param status          status for exploratory environment.
+     */
+    private void updateComputationalStatuses(String user, String project, String exploratoryName, UserInstanceStatus status) {
+        log.debug("updating status for all computational resources of {} for user {}: {}", exploratoryName, user,
+                status);
+        computationalDAO.updateComputationalStatusesForExploratory(new ExploratoryStatusDTO()
+                .withUser(user)
+                .withExploratoryName(exploratoryName)
+                .withProject(project)
+                .withStatus(status));
+    }
+
+    private void updateComputationalStatuses(String user, String project, String exploratoryName, UserInstanceStatus
+            dataEngineStatus, UserInstanceStatus dataEngineServiceStatus, UserInstanceStatus... excludedStatuses) {
+        log.debug("updating status for all computational resources of {} for user {}: DataEngine {}, " +
+                "dataengine-service {}", exploratoryName, user, dataEngineStatus, dataEngineServiceStatus);
+        computationalDAO.updateComputationalStatusesForExploratory(user, project, exploratoryName,
+                dataEngineStatus, dataEngineServiceStatus, excludedStatuses);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/GitCredsCallback.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/GitCredsCallback.java
new file mode 100644
index 0000000..95ea583
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/GitCredsCallback.java
@@ -0,0 +1,64 @@
+/*
+ * 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.datalab.backendapi.resources.callback;
+
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.exploratory.ExploratoryStatusDTO;
+import com.epam.datalab.rest.contracts.ApiCallbacks;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+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;
+
+@Path("/user/git_creds")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class GitCredsCallback {
+
+    @Inject
+    private RequestId requestId;
+
+    /**
+     * Update GIT credentials status in Mongo DB for user.
+     *
+     * @param dto description of status.
+     * @return 200 OK - if request success.
+     */
+    @POST
+    @Path(ApiCallbacks.STATUS_URI)
+    public Response status(ExploratoryStatusDTO dto) {
+        if (UserInstanceStatus.CREATED != UserInstanceStatus.of(dto.getStatus())) {
+            log.error("Git creds has not been updated for exploratory environment {} for user {}, status is {}",
+                    dto.getExploratoryName(), dto.getUser(), dto.getStatus());
+        } else {
+            log.debug("Git creds has been updated for exploratory environment {} for user {}, status is {}",
+                    dto.getExploratoryName(), dto.getUser(), dto.getStatus());
+        }
+        requestId.checkAndRemove(dto.getRequestId());
+        return Response.ok().build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ImageCallback.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ImageCallback.java
new file mode 100644
index 0000000..587c8ea
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ImageCallback.java
@@ -0,0 +1,71 @@
+/*
+ * 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.datalab.backendapi.resources.callback;
+
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.ImageExploratoryService;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.exploratory.ImageCreateStatusDTO;
+import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.epam.datalab.model.exploratory.Image;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+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;
+
+@Path("/infrastructure_provision/image")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ImageCallback {
+
+    @Inject
+    private ImageExploratoryService imageExploratoryService;
+    @Inject
+    private RequestId requestId;
+
+    @POST
+    @Path("/image_status")
+    public Response imageCreateStatus(ImageCreateStatusDTO dto) {
+        log.debug("Updating status of image {} for user {} to {}", dto.getName(), dto.getUser(), dto);
+        requestId.remove(dto.getRequestId());
+        imageExploratoryService.finishImageCreate(getImage(dto), dto.getExploratoryName(), dto.getImageCreateDTO()
+                .getIp());
+        return Response.status(Response.Status.CREATED).build();
+    }
+
+    private Image getImage(ImageCreateStatusDTO dto) {
+        return Image.builder()
+                .name(dto.getName())
+                .user(dto.getUser())
+                .project(dto.getProject())
+                .endpoint(dto.getEndpoint())
+                .externalName(dto.getImageCreateDTO().getExternalName())
+                .fullName(dto.getImageCreateDTO().getFullName())
+                .status(UserInstanceStatus.FAILED == UserInstanceStatus.of(dto.getStatus()) ?
+                        ImageStatus.FAILED : dto.getImageCreateDTO().getStatus())
+                .application(dto.getImageCreateDTO().getApplication()).build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/LibraryCallback.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/LibraryCallback.java
new file mode 100644
index 0000000..e3d69ad
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/LibraryCallback.java
@@ -0,0 +1,98 @@
+/*
+ * 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.datalab.backendapi.resources.callback;
+
+import com.epam.datalab.backendapi.dao.ExploratoryLibDAO;
+import com.epam.datalab.backendapi.domain.ExploratoryLibCache;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.exploratory.LibInstallStatusDTO;
+import com.epam.datalab.dto.exploratory.LibListStatusDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+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;
+
+@Path("/infrastructure_provision/library")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class LibraryCallback {
+
+    @Inject
+    private ExploratoryLibDAO libraryDAO;
+    @Inject
+    private RequestId requestId;
+
+    /**
+     * Changes the status of installed libraries for exploratory environment.
+     *
+     * @param dto description of status.
+     * @return 200 OK - if request success.
+     */
+    @POST
+    @Path("/lib_status")
+    public Response libInstallStatus(LibInstallStatusDTO dto) {
+        log.debug("Updating status of libraries for exploratory environment {} for user {} to {}",
+                dto.getExploratoryName(), dto.getUser(), dto);
+        requestId.checkAndRemove(dto.getRequestId());
+        try {
+            libraryDAO.updateLibraryFields(dto);
+        } catch (DatalabException e) {
+            log.error("Cannot update status of libraries for exploratory environment {} for user {} to {}",
+                    dto.getExploratoryName(), dto.getUser(), dto, e);
+            throw new DatalabException("Cannot update status of libaries for exploratory environment " + dto.getExploratoryName() +
+                    " for user " + dto.getUser() + ": " + e.getLocalizedMessage(), e);
+        }
+
+        return Response.ok().build();
+    }
+
+
+    /**
+     * Updates the list of libraries.
+     *
+     * @param dto DTO the list of libraries.
+     * @return Always return code 200 (OK).
+     */
+    @POST
+    @Path("/update_lib_list")
+    public Response updateLibList(LibListStatusDTO dto) {
+        log.debug("Updating the list of libraries for image {}", dto.getGroup());
+        requestId.checkAndRemove(dto.getRequestId());
+        try {
+            if (UserInstanceStatus.FAILED == UserInstanceStatus.of(dto.getStatus())) {
+                log.warn("Request for the list of libraries for {} fails: {}", dto.getGroup(), dto.getErrorMessage());
+                ExploratoryLibCache.getCache().updateLibListStatus(dto.getGroup());
+            } else {
+                ExploratoryLibCache.getCache().updateLibList(dto.getGroup(), dto.getLibs());
+            }
+        } catch (Exception e) {
+            log.warn("Cannot update the list of libs: {}", e.getLocalizedMessage(), e);
+        }
+        return Response.ok().build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ProjectCallback.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ProjectCallback.java
new file mode 100644
index 0000000..3ac6d02
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ProjectCallback.java
@@ -0,0 +1,73 @@
+/*
+ * 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.datalab.backendapi.resources.callback;
+
+import com.epam.datalab.backendapi.dao.ProjectDAO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.project.ProjectResult;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+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;
+import java.util.Objects;
+
+@Path("/project/status")
+@Consumes(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ProjectCallback {
+
+    private final ProjectDAO projectDAO;
+    private final ExploratoryService exploratoryService;
+    private final RequestId requestId;
+
+    @Inject
+    public ProjectCallback(ProjectDAO projectDAO, ExploratoryService exploratoryService, RequestId requestId) {
+        this.projectDAO = projectDAO;
+        this.exploratoryService = exploratoryService;
+        this.requestId = requestId;
+    }
+
+
+    @POST
+    public Response updateProjectStatus(ProjectResult projectResult) {
+        requestId.checkAndRemove(projectResult.getRequestId());
+        final String projectName = projectResult.getProjectName();
+        final UserInstanceStatus status = UserInstanceStatus.of(projectResult.getStatus());
+        if (UserInstanceStatus.RUNNING == status && Objects.nonNull(projectResult.getEdgeInfo())) {
+            projectDAO.updateEdgeInfo(projectName, projectResult.getEndpointName(), projectResult.getEdgeInfo());
+        } else {
+            updateExploratoriesStatusIfNeeded(status, projectResult.getProjectName(), projectResult.getEndpointName());
+            projectDAO.updateEdgeStatus(projectName, projectResult.getEndpointName(), status);
+        }
+        return Response.ok().build();
+    }
+
+    private void updateExploratoriesStatusIfNeeded(UserInstanceStatus status, String projectName, String endpoint) {
+        if (UserInstanceStatus.TERMINATED == status) {
+            exploratoryService.updateProjectExploratoryStatuses(projectName, endpoint, UserInstanceStatus.TERMINATED);
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ReuploadKeyCallback.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ReuploadKeyCallback.java
new file mode 100644
index 0000000..de371d8
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ReuploadKeyCallback.java
@@ -0,0 +1,56 @@
+/*
+ * 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.datalab.backendapi.resources.callback;
+
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.ReuploadKeyService;
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyStatusDTO;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+@Path("infrastructure/reupload_key")
+@Consumes(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ReuploadKeyCallback {
+
+    @Inject
+    private RequestId requestId;
+    @Inject
+    private ReuploadKeyService reuploadKeyService;
+
+    @Context
+    private UriInfo uriInfo;
+
+    @POST
+    @Path("/callback")
+    public Response reuploadKeyResponse(ReuploadKeyStatusDTO dto) {
+        requestId.remove(dto.getRequestId());
+        reuploadKeyService.updateResourceData(dto);
+        return Response.ok(uriInfo.getRequestUri()).build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BackupFormDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BackupFormDTO.java
new file mode 100644
index 0000000..42ca342
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BackupFormDTO.java
@@ -0,0 +1,40 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import lombok.Data;
+import lombok.ToString;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import java.util.List;
+
+@Data
+@ToString
+public class BackupFormDTO {
+    @NotEmpty
+    private final List<String> configFiles;
+    @NotEmpty
+    private final List<String> keys;
+    @NotEmpty
+    private final List<String> certificates;
+    private final List<String> jars;
+    private final boolean databaseBackup;
+    private final boolean logsBackup;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BackupInfoRecord.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BackupInfoRecord.java
new file mode 100644
index 0000000..e8425f9
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BackupInfoRecord.java
@@ -0,0 +1,45 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.dto.backup.EnvBackupStatus;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BackupInfoRecord {
+
+    private final List<String> configFiles;
+    private final List<String> keys;
+    private final List<String> certificates;
+    private final List<String> jars;
+    private final boolean databaseBackup;
+    private final boolean logsBackup;
+    private final String backupFile;
+    private final EnvBackupStatus status;
+    @JsonProperty("error_message")
+    private final String errorMessage;
+    private final Date timestamp;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BillingFilter.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BillingFilter.java
new file mode 100644
index 0000000..0de99d8
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BillingFilter.java
@@ -0,0 +1,58 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.NonNull;
+
+import java.util.Collections;
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BillingFilter {
+    @NonNull
+    private List<String> users;
+    @NonNull
+    @JsonProperty("datalab_id")
+    private String datalabId;
+    @NonNull
+    @JsonProperty("date_start")
+    private String dateStart;
+    @NonNull
+    @JsonProperty("date_end")
+    private String dateEnd;
+    @NonNull
+    @JsonProperty("resource_type")
+    private List<String> resourceTypes;
+    @NonNull
+    private List<UserInstanceStatus> statuses = Collections.emptyList();
+    @NonNull
+    private List<String> projects;
+    @NonNull
+    private List<String> products;
+    @NonNull
+    private List<String> shapes;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BucketDeleteDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BucketDeleteDTO.java
new file mode 100644
index 0000000..7787ec0
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BucketDeleteDTO.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import java.util.List;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BucketDeleteDTO {
+    @NotBlank(message = "field cannot be empty")
+    private final String bucket;
+    @NotBlank(message = "field cannot be empty")
+    private final String endpoint;
+    @NotEmpty(message = "field cannot be empty")
+    private final List<String> objects;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BucketDownloadDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BucketDownloadDTO.java
new file mode 100644
index 0000000..8a80711
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/BucketDownloadDTO.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BucketDownloadDTO {
+    @NotBlank(message = "field cannot be empty")
+    private final String bucket;
+    @NotBlank(message = "field cannot be empty")
+    private final String object;
+    @NotBlank(message = "field cannot be empty")
+    private final String endpoint;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ComputationalCreateFormDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ComputationalCreateFormDTO.java
new file mode 100644
index 0000000..f4520ba
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ComputationalCreateFormDTO.java
@@ -0,0 +1,64 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * Stores info about creation of the computational resource.
+ */
+@Data
+public class ComputationalCreateFormDTO {
+
+    @NotBlank
+    @JsonProperty("template_name")
+    private String templateName;
+
+    @NotBlank
+    @JsonProperty
+    private String image;
+
+    @NotBlank
+    @JsonProperty
+    private String name;
+
+    @NotBlank
+    @JsonProperty
+    private String project;
+    @JsonProperty("custom_tag")
+    private String customTag;
+
+    @NotBlank
+    @JsonProperty("notebook_name")
+    private String notebookName;
+
+    @JsonProperty("check_inactivity_required")
+    private boolean checkInactivityRequired = true;
+
+    @Valid
+    private List<ClusterConfig> config;
+
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ComputationalTemplatesDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ComputationalTemplatesDTO.java
new file mode 100644
index 0000000..15bec62
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ComputationalTemplatesDTO.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.dto.base.computational.FullComputationalTemplate;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ComputationalTemplatesDTO {
+    private final List<FullComputationalTemplate> templates;
+    @JsonProperty("user_computations")
+    private final List<String> userComputations;
+    @JsonProperty("project_computations")
+    private final List<String> projectComputations;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryActionFormDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryActionFormDTO.java
new file mode 100644
index 0000000..d02599e7f
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryActionFormDTO.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.validator.constraints.NotBlank;
+
+/**
+ * Stores info about action on the exploratory resource.
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ExploratoryActionFormDTO {
+    @NotBlank
+    @JsonProperty("notebook_instance_name")
+    private String notebookInstanceName;
+
+    @NotBlank
+    @JsonProperty("project_name")
+    private String projectName;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryCreateFormDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryCreateFormDTO.java
new file mode 100644
index 0000000..d703563
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryCreateFormDTO.java
@@ -0,0 +1,188 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import org.hibernate.validator.constraints.NotBlank;
+
+import java.util.List;
+
+/**
+ * Stores info about new exploratory.
+ */
+public class ExploratoryCreateFormDTO {
+    @NotBlank
+    @JsonProperty
+    private String image;
+
+    @NotBlank
+    @JsonProperty("template_name")
+    private String templateName;
+
+    @NotBlank
+    @JsonProperty
+    private String name;
+
+    @NotBlank
+    @JsonProperty
+    private String project;
+    @JsonProperty("custom_tag")
+    private String exploratoryTag;
+
+    @NotBlank
+    @JsonProperty
+    private String endpoint;
+
+    @NotBlank
+    @JsonProperty
+    private String shape;
+
+    @NotBlank
+    @JsonProperty
+    private String version;
+
+    @JsonProperty("notebook_image_name")
+    private String imageName;
+
+    @JsonProperty("cluster_config")
+    private List<ClusterConfig> clusterConfig;
+
+    /**
+     * Returns the image name of notebook.
+     */
+    public String getImage() {
+        return image;
+    }
+
+    /**
+     * Sets the image name of notebook.
+     */
+    public void setImage(String image) {
+        this.image = image;
+    }
+
+    /**
+     * Returns name of template.
+     */
+    public String getTemplateName() {
+        return templateName;
+    }
+
+    /**
+     * Sets name of template.
+     */
+    public void setTemplateName(String templateName) {
+        this.templateName = templateName;
+    }
+
+    /**
+     * Returns name of notebook.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets name of notebook.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns name of shape.
+     */
+    public String getShape() {
+        return shape;
+    }
+
+    /**
+     * Sets name of shape.
+     */
+    public void setShape(String shape) {
+        this.shape = shape;
+    }
+
+    /**
+     * Returns version.
+     */
+    public String getVersion() {
+        return version;
+    }
+
+    /**
+     * Sets version.
+     */
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    /**
+     * Returns image name from which notebook should be created
+     */
+    public String getImageName() {
+        return imageName;
+    }
+
+    /**
+     * Sets image name from which notebook should be created
+     */
+    public void setImageName(String imageName) {
+        this.imageName = imageName;
+    }
+
+    public List<ClusterConfig> getClusterConfig() {
+        return clusterConfig;
+    }
+
+    public String getProject() {
+        return project;
+    }
+
+    public void setProject(String project) {
+        this.project = project;
+    }
+
+    public String getEndpoint() {
+        return endpoint;
+    }
+
+    public void setEndpoint(String endpoint) {
+        this.endpoint = endpoint;
+    }
+
+    public String getExploratoryTag() {
+        return exploratoryTag;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("name", name)
+                .add("templateName", templateName)
+                .add("shape", shape)
+                .add("version", version)
+                .add("image", image)
+                .add("imageName", imageName)
+                .toString();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryCreatePopUp.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryCreatePopUp.java
new file mode 100644
index 0000000..4367244
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryCreatePopUp.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class ExploratoryCreatePopUp {
+    @JsonProperty("user_projects")
+    private final List<ProjectDTO> userProjects;
+    @JsonProperty("project_exploratories")
+    private final Map<String, List<String>> projectExploratories;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormDTO.java
new file mode 100644
index 0000000..a60c54d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormDTO.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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.ToString;
+import org.hibernate.validator.constraints.NotBlank;
+
+@Data
+@ToString
+public class ExploratoryImageCreateFormDTO {
+    @NotBlank
+    private final String name;
+    @NotBlank
+    @JsonProperty("exploratory_name")
+    private String notebookName;
+    @NotBlank
+    @JsonProperty("project_name")
+    private String projectName;
+    private final String description;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/FolderUploadDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/FolderUploadDTO.java
new file mode 100644
index 0000000..5ae9086
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/FolderUploadDTO.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class FolderUploadDTO {
+    @NotBlank(message = "field cannot be empty")
+    private final String bucket;
+    @NotBlank(message = "field cannot be empty")
+    private final String folder;
+    @NotBlank(message = "field cannot be empty")
+    private final String endpoint;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/GroupDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/GroupDTO.java
new file mode 100644
index 0000000..3439a6c
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/GroupDTO.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+@Getter
+@Setter
+public class GroupDTO {
+    @NotEmpty
+    private String name;
+    @NotEmpty
+    private Map<String, String> roleIds;
+    private Set<String> users = Collections.emptySet();
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusDTO.java
new file mode 100644
index 0000000..3182e68
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusDTO.java
@@ -0,0 +1,85 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+/**
+ * Stores the health statuses for services.
+ */
+public class HealthStatusDTO {
+    @JsonProperty("mongo_alive")
+    private boolean mongoAlive;
+    @JsonProperty("provisioning_alive")
+    private boolean provisioningAlive;
+
+    /**
+     * Returns <b>true</b> if the Mongo database is available.
+     */
+    public boolean isMongoAlive() {
+        return mongoAlive;
+    }
+
+    /**
+     * Sets the Mongo database availability.
+     */
+    public void setMongoAlive(boolean mongoAlive) {
+        this.mongoAlive = mongoAlive;
+    }
+
+    /**
+     * Sets the Mongo database availability.
+     */
+    public HealthStatusDTO withMongoAlive(boolean mongoAlive) {
+        setMongoAlive(mongoAlive);
+        return this;
+    }
+
+    /**
+     * Returns <b>true</b> if the provisioning service is available.
+     */
+    public boolean isProvisioningAlive() {
+        return provisioningAlive;
+    }
+
+    /**
+     * Sets the provisioning service availability.
+     */
+    public void setProvisioningAlive(boolean provisioningAlive) {
+        this.provisioningAlive = provisioningAlive;
+    }
+
+    /**
+     * Sets the provisioning service availability.
+     */
+    public HealthStatusDTO withProvisioningAlive(boolean provisioningAlive) {
+        setProvisioningAlive(provisioningAlive);
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("mongoAlive", mongoAlive)
+                .add("provisioningAlive", provisioningAlive)
+                .toString();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusEnum.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusEnum.java
new file mode 100644
index 0000000..e08531f
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusEnum.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+/**
+ * Statuses for the environment resource.
+ */
+public enum HealthStatusEnum {
+    ERROR,
+    WARNING,
+    OK;
+
+    @Override
+    public String toString() {
+        return super.toString().toLowerCase();
+    }
+
+    public static HealthStatusEnum of(String status) {
+        if (status != null) {
+            for (HealthStatusEnum uis : HealthStatusEnum.values()) {
+                if (status.equalsIgnoreCase(uis.toString())) {
+                    return uis;
+                }
+            }
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusPageDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusPageDTO.java
new file mode 100644
index 0000000..9db1cfc
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusPageDTO.java
@@ -0,0 +1,59 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+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 auditEnabled;
+    @JsonProperty
+    private boolean admin;
+    @JsonProperty
+    private boolean projectAdmin;
+    @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
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusResource.java
new file mode 100644
index 0000000..5516160
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusResource.java
@@ -0,0 +1,110 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+/**
+ * Stores the health status for user environment.
+ */
+public class HealthStatusResource {
+    @JsonProperty("type")
+    private String type;
+    @JsonProperty("resource_id")
+    private String resourceId;
+    @JsonProperty("status")
+    private String status;
+
+    /**
+     * Return the type of resource.
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Set the type of resource.
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Set the type of resource.
+     */
+    public HealthStatusResource withType(String type) {
+        setType(type);
+        return this;
+    }
+
+    /**
+     * Return the id of resource (ip address, path, etc).
+     */
+    public String getResourceId() {
+        return resourceId;
+    }
+
+    /**
+     * Set the id of resource (ip address, path, etc).
+     */
+    public void setResourceId(String resourceId) {
+        this.resourceId = resourceId;
+    }
+
+    /**
+     * Set the id of resource (ip address, path, etc).
+     */
+    public HealthStatusResource withResourceId(String resourceId) {
+        setResourceId(resourceId);
+        return this;
+    }
+
+    /**
+     * Return the status of resource.
+     */
+    public String getStatus() {
+        return status;
+    }
+
+    /**
+     * Set the status of resource.
+     */
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    /**
+     * Set the status of resource.
+     */
+    public HealthStatusResource withStatus(String status) {
+        setStatus(status);
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("type", type)
+                .add("resourceId", resourceId)
+                .add("status", status)
+                .toString();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageInfoRecord.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageInfoRecord.java
new file mode 100644
index 0000000..18692c3
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageInfoRecord.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ImageInfoRecord {
+    private final String name;
+    private final String description;
+    private final String project;
+    private final String endpoint;
+    private final String user;
+    private final String application;
+    private final String fullName;
+    private final ImageStatus status;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/KeysDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/KeysDTO.java
new file mode 100644
index 0000000..9ed760b
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/KeysDTO.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.datalab.backendapi.resources.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@AllArgsConstructor
+@Data
+public class KeysDTO {
+    private String publicKey;
+    private String privateKey;
+    private String username;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibInfoRecord.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibInfoRecord.java
new file mode 100644
index 0000000..27571f1
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibInfoRecord.java
@@ -0,0 +1,43 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class LibInfoRecord {
+    @JsonProperty
+    @JsonUnwrapped
+    private LibKey libKey;
+
+    @JsonProperty
+    private List<LibraryStatus> status;
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibInstallFormDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibInstallFormDTO.java
new file mode 100644
index 0000000..0c9c603
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibInstallFormDTO.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.dto.exploratory.LibInstallDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import java.util.List;
+
+/**
+ * Stores info about the installation of libraries.
+ */
+@Data
+public class LibInstallFormDTO {
+    @NotBlank
+    @JsonProperty("exploratory_name")
+    private String notebookName;
+
+    @JsonProperty("computational_name")
+    private String computationalName;
+
+    @JsonProperty("project_name")
+    private String project;
+
+    @NotEmpty
+    @JsonProperty
+    private List<LibInstallDTO> libs;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibKey.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibKey.java
new file mode 100644
index 0000000..7337bdc
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibKey.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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class LibKey {
+    @JsonProperty
+    private String name;
+    @JsonProperty
+    private String version;
+    @JsonProperty
+    private String group;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibraryAutoCompleteDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibraryAutoCompleteDTO.java
new file mode 100644
index 0000000..98fa4f5
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibraryAutoCompleteDTO.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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.backendapi.domain.AutoCompleteEnum;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Builder
+public class LibraryAutoCompleteDTO {
+    private AutoCompleteEnum autoComplete;
+    private List<LibraryDTO> libraries;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibraryDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibraryDTO.java
new file mode 100644
index 0000000..5ec5674
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibraryDTO.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.datalab.backendapi.resources.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+public class LibraryDTO {
+    private String name;
+    private String version;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibraryStatus.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibraryStatus.java
new file mode 100644
index 0000000..b503007
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/LibraryStatus.java
@@ -0,0 +1,47 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class LibraryStatus {
+    @JsonProperty
+    private String resource;
+    @JsonProperty
+    private String resourceType;
+    @JsonProperty
+    private String status;
+    @JsonProperty
+    private String error;
+    @JsonProperty("available_versions")
+    private List<String> availableVersions;
+    @JsonProperty("add_pkgs")
+    private List<String> addedPackages;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ProjectActionFormDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ProjectActionFormDTO.java
new file mode 100644
index 0000000..9f6e61e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ProjectActionFormDTO.java
@@ -0,0 +1,36 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@Data
+public class ProjectActionFormDTO {
+    @NotNull
+    @JsonProperty("project_name")
+    private final String projectName;
+    @NotNull
+    @JsonProperty("endpoint")
+    private final List<String> endpoints;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ProjectInfrastructureInfo.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ProjectInfrastructureInfo.java
new file mode 100644
index 0000000..20605d2
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ProjectInfrastructureInfo.java
@@ -0,0 +1,51 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.backendapi.domain.BillingReport;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.List;
+import java.util.Map;
+
+@AllArgsConstructor
+@Builder
+@EqualsAndHashCode
+@ToString
+public class ProjectInfrastructureInfo {
+    @JsonProperty
+    private String project;
+    @JsonProperty
+    private int billingQuoteUsed;
+    @JsonProperty
+    private Map<String, Map<String, String>> shared;
+    @JsonProperty
+    private List<UserInstanceDTO> exploratory;
+    @JsonProperty
+    private List<BillingReport> exploratoryBilling;
+    @JsonProperty
+    private List<EndpointDTO> endpoints;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/QuotaUsageDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/QuotaUsageDTO.java
new file mode 100644
index 0000000..7f4d3a2
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/QuotaUsageDTO.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.datalab.backendapi.resources.dto;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+@Builder
+public class QuotaUsageDTO {
+    private int totalQuotaUsed;
+    private Map<String, Integer> projectQuotas;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SearchLibsFormDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SearchLibsFormDTO.java
new file mode 100644
index 0000000..509cab5
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SearchLibsFormDTO.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
+
+@Data
+public class SearchLibsFormDTO {
+    @NotBlank
+    @JsonProperty("exploratory_name")
+    private String notebookName;
+
+    @NotBlank
+    @JsonProperty("project_name")
+    private String projectName;
+
+    @NotBlank
+    @JsonProperty
+    private String group;
+
+    @NotBlank
+    @JsonProperty("start_with")
+    private String startWith;
+
+    @JsonProperty("computational_name")
+    private String computationalName;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SparkStandaloneClusterCreateForm.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SparkStandaloneClusterCreateForm.java
new file mode 100644
index 0000000..0178dff
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SparkStandaloneClusterCreateForm.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.hibernate.validator.constraints.NotBlank;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class SparkStandaloneClusterCreateForm extends ComputationalCreateFormDTO {
+
+    @NotBlank
+    @JsonProperty("dataengine_instance_count")
+    private String dataEngineInstanceCount;
+
+    @NotBlank
+    @JsonProperty("dataengine_instance_shape")
+    private String dataEngineInstanceShape;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SparkStandaloneConfiguration.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SparkStandaloneConfiguration.java
new file mode 100644
index 0000000..83603b7
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SparkStandaloneConfiguration.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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class SparkStandaloneConfiguration {
+    @JsonProperty("min_spark_instance_count")
+    private int minSparkInstanceCount;
+    @JsonProperty("max_spark_instance_count")
+    private int maxSparkInstanceCount;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SystemInfoDto.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SystemInfoDto.java
new file mode 100644
index 0000000..3b945a7
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SystemInfoDto.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.model.systeminfo.DiskInfo;
+import com.epam.datalab.model.systeminfo.MemoryInfo;
+import com.epam.datalab.model.systeminfo.OsInfo;
+import com.epam.datalab.model.systeminfo.ProcessorInfo;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+
+@AllArgsConstructor
+@Getter
+public class SystemInfoDto {
+
+    @JsonProperty
+    private OsInfo osInfo;
+    @JsonProperty
+    private ProcessorInfo processorInfo;
+    @JsonProperty
+    private MemoryInfo memoryInfo;
+    @JsonProperty
+    private List<DiskInfo> disksInfo;
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UpdateGroupDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UpdateGroupDTO.java
new file mode 100644
index 0000000..9d3c37b
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UpdateGroupDTO.java
@@ -0,0 +1,38 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+@Getter
+@Setter
+public class UpdateGroupDTO {
+    @NotEmpty
+    private String name;
+    @NotEmpty
+    private Map<String, String> roles;
+    private Set<String> users = Collections.emptySet();
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UpdateRoleGroupDto.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UpdateRoleGroupDto.java
new file mode 100644
index 0000000..c78748e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UpdateRoleGroupDto.java
@@ -0,0 +1,36 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import java.util.Set;
+
+@AllArgsConstructor
+@Getter
+public class UpdateRoleGroupDto {
+
+    @NotEmpty
+    private final Set<String> roleIds;
+    @NotEmpty
+    private final String group;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UpdateUserGroupDto.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UpdateUserGroupDto.java
new file mode 100644
index 0000000..308a3bb
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UpdateUserGroupDto.java
@@ -0,0 +1,36 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import java.util.Set;
+
+@AllArgsConstructor
+@Getter
+public class UpdateUserGroupDto {
+
+    @NotEmpty
+    private final String group;
+    @NotEmpty
+    private final Set<String> users;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserDTO.java
new file mode 100644
index 0000000..96f74f4
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserDTO.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.datalab.backendapi.resources.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+@Data
+@AllArgsConstructor
+public class UserDTO {
+    @NotNull
+    private final String name;
+    @Min(1)
+    private final Integer budget;
+    private Status status;
+
+    public enum Status {
+        ACTIVE, NOT_ACTIVE
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserGroupDto.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserGroupDto.java
new file mode 100644
index 0000000..024375d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserGroupDto.java
@@ -0,0 +1,36 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+import java.util.Set;
+
+@AllArgsConstructor
+@Getter
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UserGroupDto {
+    private final String group;
+    private final List<UserRoleDto> roles;
+    private final Set<String> users;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserResourceInfo.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserResourceInfo.java
new file mode 100644
index 0000000..135fbaa
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserResourceInfo.java
@@ -0,0 +1,57 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.dto.ResourceURL;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.model.ResourceEnum;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Builder
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UserResourceInfo {
+    @JsonProperty
+    private String user;
+    @JsonProperty
+    private String project;
+    @JsonProperty
+    private String endpoint;
+    @JsonProperty("resource_type")
+    private ResourceEnum resourceType;
+    @JsonProperty("resource_name")
+    private String resourceName;
+    @JsonProperty("shape")
+    private String resourceShape;
+    @JsonProperty("status")
+    private String resourceStatus;
+    @JsonProperty("computational_resources")
+    private List<UserComputationalResource> computationalResources;
+    @JsonProperty("public_ip")
+    private String ip;
+    @JsonProperty("cloud_provider")
+    private String cloudProvider;
+    @JsonProperty("exploratory_urls")
+    private List<ResourceURL> exploratoryUrls;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserRoleDto.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserRoleDto.java
new file mode 100644
index 0000000..374e8ba
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserRoleDto.java
@@ -0,0 +1,64 @@
+/*
+ * 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.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.cloud.CloudProvider;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+@Getter
+@Setter
+@ToString
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UserRoleDto {
+    @JsonProperty("_id")
+    private String id;
+    private String description;
+    private Type type;
+    private CloudProvider cloud;
+    private Set<String> pages;
+    private Set<String> computationals;
+    private Set<String> exploratories;
+    @JsonProperty("exploratory_shapes")
+    private Set<String> exploratoryShapes;
+    @JsonProperty("computational_shapes")
+    private Set<String> computationalShapes;
+    private Set<String> groups;
+
+    private enum Type {
+        NOTEBOOK,
+        COMPUTATIONAL,
+        NOTEBOOK_SHAPE,
+        COMPUTATIONAL_SHAPE,
+        BILLING,
+        BUCKET_BROWSER,
+        ADMINISTRATION
+    }
+
+    public static List<Type> cloudSpecificTypes() {
+        return Arrays.asList(Type.NOTEBOOK, Type.COMPUTATIONAL, Type.NOTEBOOK_SHAPE, Type.COMPUTATIONAL_SHAPE);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/aws/AwsComputationalCreateForm.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/aws/AwsComputationalCreateForm.java
new file mode 100644
index 0000000..5b536ee
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/aws/AwsComputationalCreateForm.java
@@ -0,0 +1,57 @@
+/*
+ * 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.datalab.backendapi.resources.dto.aws;
+
+import com.epam.datalab.backendapi.resources.dto.ComputationalCreateFormDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.hibernate.validator.constraints.NotBlank;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class AwsComputationalCreateForm extends ComputationalCreateFormDTO {
+
+    @NotBlank
+    @JsonProperty("emr_instance_count")
+    private String instanceCount;
+
+    @NotBlank
+    @JsonProperty("emr_master_instance_type")
+    private String masterInstanceType;
+
+    @NotBlank
+    @JsonProperty("emr_slave_instance_type")
+    private String slaveInstanceType;
+
+    @JsonProperty("emr_slave_instance_spot")
+    private Boolean slaveInstanceSpot = false;
+
+    @JsonProperty("emr_slave_instance_spot_pct_price")
+    private Integer slaveInstanceSpotPctPrice;
+
+    @NotBlank
+    @JsonProperty("emr_version")
+    private String version;
+
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/aws/AwsEmrConfiguration.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/aws/AwsEmrConfiguration.java
new file mode 100644
index 0000000..21161b8
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/aws/AwsEmrConfiguration.java
@@ -0,0 +1,49 @@
+/*
+ * 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.datalab.backendapi.resources.dto.aws;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
+
+/**
+ * Stores limits for creation of the computational resources for EMR cluster
+ */
+@Data
+@Builder
+public class AwsEmrConfiguration {
+    @NotBlank
+    @JsonProperty("min_emr_instance_count")
+    private int minEmrInstanceCount;
+
+    @NotBlank
+    @JsonProperty("max_emr_instance_count")
+    private int maxEmrInstanceCount;
+
+    @NotBlank
+    @JsonProperty("min_emr_spot_instance_bid_pct")
+    private int minEmrSpotInstanceBidPct;
+
+    @NotBlank
+    @JsonProperty("max_emr_spot_instance_bid_pct")
+    private int maxEmrSpotInstanceBidPct;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/gcp/GcpComputationalCreateForm.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/gcp/GcpComputationalCreateForm.java
new file mode 100644
index 0000000..df0bfd3
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/gcp/GcpComputationalCreateForm.java
@@ -0,0 +1,53 @@
+/*
+ * 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.datalab.backendapi.resources.dto.gcp;
+
+import com.epam.datalab.backendapi.resources.dto.ComputationalCreateFormDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.ToString;
+import org.hibernate.validator.constraints.NotBlank;
+
+@Data
+@ToString(callSuper = true)
+public class GcpComputationalCreateForm extends ComputationalCreateFormDTO {
+
+    @NotBlank
+    @JsonProperty("dataproc_master_count")
+    private String masterInstanceCount;
+
+    @NotBlank
+    @JsonProperty("dataproc_slave_count")
+    private String slaveInstanceCount;
+
+    @NotBlank
+    @JsonProperty("dataproc_preemptible_count")
+    private String preemptibleCount;
+
+    @JsonProperty("dataproc_master_instance_type")
+    private String masterInstanceType;
+
+    @JsonProperty("dataproc_slave_instance_type")
+    private String slaveInstanceType;
+
+    @NotBlank
+    @JsonProperty("dataproc_version")
+    private String version;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/gcp/GcpDataprocConfiguration.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/gcp/GcpDataprocConfiguration.java
new file mode 100644
index 0000000..86890e8
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/gcp/GcpDataprocConfiguration.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.backendapi.resources.dto.gcp;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
+
+/**
+ * Stores limits for creation of the computational resources for Dataproc cluster
+ */
+@Data
+@Builder
+public class GcpDataprocConfiguration {
+    @NotBlank
+    @JsonProperty("min_instance_count")
+    private int minInstanceCount;
+    @NotBlank
+    @JsonProperty("max_instance_count")
+    private int maxInstanceCount;
+    @NotBlank
+    @JsonProperty("min_dataproc_preemptible_instance_count")
+    private int minDataprocPreemptibleInstanceCount;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/ComputationalResourceGcp.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/ComputationalResourceGcp.java
new file mode 100644
index 0000000..28470e4
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/ComputationalResourceGcp.java
@@ -0,0 +1,259 @@
+/*
+ * 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.datalab.backendapi.resources.gcp;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
+import com.epam.datalab.backendapi.resources.dto.gcp.GcpComputationalCreateForm;
+import com.epam.datalab.backendapi.roles.RoleType;
+import com.epam.datalab.backendapi.roles.UserRoles;
+import com.epam.datalab.backendapi.service.ComputationalService;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.gcp.computational.GcpComputationalResource;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.contracts.ComputationalAPI;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+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.List;
+
+import static com.epam.datalab.dto.UserInstanceStatus.CREATING;
+
+
+/**
+ * Provides the REST API for the computational resource on GCP.
+ */
+@Path("/gcp/infrastructure_provision/computational_resources")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ComputationalResourceGcp implements ComputationalAPI {
+    private final SelfServiceApplicationConfiguration configuration;
+    private final ComputationalService computationalService;
+
+    @Inject
+    public ComputationalResourceGcp(SelfServiceApplicationConfiguration configuration, ComputationalService computationalService) {
+        this.configuration = configuration;
+        this.computationalService = computationalService;
+    }
+
+
+    @GET
+    @Path("/{project}/{endpoint}/templates")
+    public Response getTemplates(@Auth @Parameter(hidden = true) UserInfo userInfo, @PathParam("project") String project,
+                                 @PathParam("endpoint") String endpoint) {
+        return Response.ok(computationalService.getComputationalNamesAndTemplates(userInfo, project, endpoint)).build();
+    }
+
+    /**
+     * Asynchronously creates Dataproc cluster
+     *
+     * @param userInfo user info.
+     * @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
+     */
+    @PUT
+    @Path("dataengine-service")
+    @Operation(tags = "computational", summary = "Create dataproc cluster")
+    public Response createDataEngineService(@Auth @Parameter(hidden = true) UserInfo userInfo,
+                                            @Valid @NotNull @Parameter GcpComputationalCreateForm form) {
+
+        log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
+
+        if (DataEngineType.CLOUD_SERVICE == DataEngineType.fromDockerImageName(form.getImage())) {
+            validate(userInfo, form);
+            GcpComputationalResource gcpComputationalResource = GcpComputationalResource.builder()
+                    .computationalName(form.getName())
+                    .imageName(form.getImage())
+                    .templateName(form.getTemplateName())
+                    .status(CREATING.toString())
+                    .masterShape(form.getMasterInstanceType())
+                    .slaveShape(form.getSlaveInstanceType())
+                    .slaveNumber(form.getSlaveInstanceCount())
+                    .masterNumber(form.getMasterInstanceCount())
+                    .preemptibleNumber(form.getPreemptibleCount())
+                    .version(form.getVersion())
+                    .totalInstanceCount(Integer.parseInt(form.getMasterInstanceCount()) + Integer.parseInt(form.getSlaveInstanceCount()))
+                    .build();
+            boolean resourceAdded = computationalService.createDataEngineService(userInfo, form.getName(), form, gcpComputationalResource,
+                    form.getProject(), getAuditInfo(form.getNotebookName()));
+            return resourceAdded ? Response.ok().build() : Response.status(Response.Status.FOUND).build();
+        }
+
+        throw new IllegalArgumentException("Malformed image " + form.getImage());
+    }
+
+
+    /**
+     * Asynchronously triggers creation of Spark cluster
+     *
+     * @param userInfo user info.
+     * @param form     DTO info about creation of the computational resource.
+     * @return 200 OK - if request success, 302 Found - for duplicates.
+     */
+    @PUT
+    @Path("dataengine")
+    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 DatalabException("You do not have the privileges to create a " + form.getTemplateName());
+        }
+
+        return computationalService.createSparkCluster(userInfo, form.getName(), form, form.getProject(), getAuditInfo(form.getNotebookName()))
+                ? Response.ok().build()
+                : Response.status(Response.Status.FOUND).build();
+    }
+
+
+    /**
+     * Sends request to provisioning service for termination the computational resource for user.
+     *
+     * @param userInfo          user info.
+     * @param exploratoryName   name of exploratory.
+     * @param computationalName name of computational resource.
+     * @return 200 OK if operation is successfully triggered
+     */
+    @DELETE
+    @Path("/{projectName}/{exploratoryName}/{computationalName}/terminate")
+    public Response terminate(@Auth UserInfo userInfo,
+                              @PathParam("projectName") String projectName,
+                              @PathParam("exploratoryName") String exploratoryName,
+                              @PathParam("computationalName") String computationalName) {
+        log.debug("Terminating computational resource {} for user {}", computationalName, userInfo.getName());
+
+        computationalService.terminateComputational(userInfo, userInfo.getName(), projectName, exploratoryName, computationalName, getAuditInfo(exploratoryName));
+        return Response.ok().build();
+    }
+
+    /**
+     * Sends request to provisioning service for stopping the computational resource for user.
+     *
+     * @param userInfo          user info.
+     * @param exploratoryName   name of exploratory.
+     * @param computationalName name of computational resource.
+     * @return 200 OK if operation is successfully triggered
+     */
+    @DELETE
+    @Path("/{project}/{exploratoryName}/{computationalName}/stop")
+    public Response stop(@Auth UserInfo userInfo,
+                         @PathParam("project") String project,
+                         @PathParam("exploratoryName") String exploratoryName,
+                         @PathParam("computationalName") String computationalName) {
+        log.debug("Stopping computational resource {} for user {}", computationalName, userInfo.getName());
+
+        computationalService.stopSparkCluster(userInfo, userInfo.getName(), project, exploratoryName, computationalName, getAuditInfo(exploratoryName));
+        return Response.ok().build();
+    }
+
+    /**
+     * Sends request to provisioning service for starting the computational resource for user.
+     *
+     * @param userInfo          user info.
+     * @param exploratoryName   name of exploratory.
+     * @param computationalName name of computational resource.
+     * @return 200 OK if operation is successfully triggered
+     */
+    @PUT
+    @Path("/{project}/{exploratoryName}/{computationalName}/start")
+    public Response start(@Auth UserInfo userInfo,
+                          @PathParam("exploratoryName") String exploratoryName,
+                          @PathParam("computationalName") String computationalName,
+                          @PathParam("project") String project) {
+        log.debug("Starting computational resource {} for user {}", computationalName, userInfo.getName());
+
+        computationalService.startSparkCluster(userInfo, exploratoryName, computationalName, project, getAuditInfo(exploratoryName));
+        return Response.ok().build();
+    }
+
+    @PUT
+    @Path("dataengine/{projectName}/{exploratoryName}/{computationalName}/config")
+    public Response updateDataEngineConfig(@Auth UserInfo userInfo,
+                                           @PathParam("projectName") String projectName,
+                                           @PathParam("exploratoryName") String exploratoryName,
+                                           @PathParam("computationalName") String computationalName,
+                                           @Valid @NotNull List<ClusterConfig> config) {
+
+        computationalService.updateSparkClusterConfig(userInfo, projectName, exploratoryName, computationalName, config,
+                String.format(AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE, computationalName, exploratoryName));
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/{projectName}/{exploratoryName}/{computationalName}/config")
+    public Response getClusterConfig(@Auth UserInfo userInfo,
+                                     @PathParam("projectName") String projectName,
+                                     @PathParam("exploratoryName") String exploratoryName,
+                                     @PathParam("computationalName") String computationalName) {
+        return Response.ok(computationalService.getClusterConfig(userInfo, projectName, exploratoryName, computationalName)).build();
+    }
+
+    private void validate(@Auth UserInfo userInfo, GcpComputationalCreateForm formDTO) {
+        if (!UserRoles.checkAccess(userInfo, RoleType.COMPUTATIONAL, formDTO.getImage(), userInfo.getRoles())) {
+            log.warn("Unauthorized attempt to create a {} by user {}", formDTO.getImage(), userInfo.getName());
+            throw new DatalabException("You do not have the privileges to create a " + formDTO.getTemplateName());
+        }
+
+        int slaveInstanceCount = Integer.parseInt(formDTO.getSlaveInstanceCount());
+        int masterInstanceCount = Integer.parseInt(formDTO.getMasterInstanceCount());
+        final int total = slaveInstanceCount + masterInstanceCount;
+        if (total < configuration.getMinInstanceCount()
+                || total > configuration.getMaxInstanceCount()) {
+            log.debug("Creating computational resource {} for user {} fail: Limit exceeded to creation total " +
+                            "instances. Minimum is {}, maximum is {}", formDTO.getName(), userInfo.getName(),
+                    configuration.getMinInstanceCount(), configuration.getMaxInstanceCount());
+            throw new DatalabException("Limit exceeded to creation slave instances. Minimum is " + configuration
+                    .getMinInstanceCount() + ", maximum is " + configuration.getMaxInstanceCount());
+        }
+
+        final int preemptibleInstanceCount = Integer.parseInt(formDTO.getPreemptibleCount());
+        if (preemptibleInstanceCount < configuration.getMinDataprocPreemptibleCount()) {
+            log.debug("Creating computational resource {} for user {} fail: Limit exceeded to creation preemptible " +
+                            "instances. Minimum is {}",
+                    formDTO.getName(), userInfo.getName(), configuration.getMinDataprocPreemptibleCount());
+            throw new DatalabException("Limit exceeded to creation preemptible instances. " +
+                    "Minimum is " + configuration.getMinDataprocPreemptibleCount());
+
+        }
+    }
+
+    private String getAuditInfo(String exploratoryName) {
+        return String.format(AUDIT_MESSAGE, exploratoryName);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/GcpOauthResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/GcpOauthResource.java
new file mode 100644
index 0000000..e52ec61
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/gcp/GcpOauthResource.java
@@ -0,0 +1,65 @@
+/*
+ * 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.datalab.backendapi.resources.gcp;
+
+import com.epam.datalab.auth.contract.SecurityAPI;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.gcp.auth.GcpOauth2AuthorizationCodeResponse;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.net.URI;
+
+@Path("/user/gcp")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class GcpOauthResource {
+
+	@Inject
+	@Named(ServiceConsts.SECURITY_SERVICE_NAME)
+	private RESTService securityService;
+
+
+	@GET
+	@Path("/init")
+	public Response redirectedUrl() {
+		return Response
+				.seeOther(URI.create(securityService.get(SecurityAPI.INIT_LOGIN_OAUTH_GCP, String.class)))
+				.build();
+	}
+
+	@GET
+	@Path("/oauth")
+	public Response login(@QueryParam("code") String code, @QueryParam("state") String state,
+						  @QueryParam("error") String error) {
+		return securityService.post(SecurityAPI.LOGIN_OAUTH,
+				new GcpOauth2AuthorizationCodeResponse(code, state, error),
+				Response.class);
+	}
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/RoleType.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/RoleType.java
new file mode 100644
index 0000000..998e01f
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/RoleType.java
@@ -0,0 +1,55 @@
+/*
+ * 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.datalab.backendapi.roles;
+
+/**
+ * Types of roles.
+ */
+public enum RoleType {
+    COMPUTATIONAL("computationals"),
+    EXPLORATORY("exploratories"),
+    EXPLORATORY_SHAPES("exploratory_shapes"),
+    COMPUTATIONAL_SHAPES("computational_shapes"),
+    PAGE("pages");
+
+    private String nodeName;
+
+    RoleType(String nodeName) {
+        this.nodeName = nodeName;
+    }
+
+    public static RoleType of(String name) {
+        if (name != null) {
+            for (RoleType value : RoleType.values()) {
+                if (name.equalsIgnoreCase(value.toString())) {
+                    return value;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Return name of node in JSON for type.
+     */
+    public String getNodeName() {
+        return nodeName;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/UserRole.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/UserRole.java
new file mode 100644
index 0000000..f9f85a6
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/UserRole.java
@@ -0,0 +1,142 @@
+/*
+ * 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.datalab.backendapi.roles;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+
+import javax.annotation.Nonnull;
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Describe role.
+ */
+public class UserRole implements Comparable<UserRole> {
+
+    private final String id;
+    /**
+     * Type of role.
+     */
+    private final RoleType type;
+
+    /**
+     * Name of role.
+     */
+    private final String name;
+
+    /**
+     * Names of external groups.
+     */
+    private final Set<String> groups;
+
+    /**
+     * Name of DataLab's users.
+     */
+    private final Set<String> users;
+
+    /**
+     * Instantiate the role.
+     *
+     * @param id
+     * @param type   type of role.
+     * @param name   the name of role.
+     * @param groups the names of external groups.
+     * @param users  the name of DataLab's users.
+     */
+    UserRole(String id, RoleType type, String name, Set<String> groups, Set<String> users) {
+        this.id = id;
+        this.type = type;
+        this.name = name;
+        this.groups = groups;
+        this.users = users;
+    }
+
+    /**
+     * Return the type of role.
+     */
+    public RoleType getType() {
+        return type;
+    }
+
+    /**
+     * Return the name of role.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Return the names of external groups.
+     */
+    public Set<String> getGroups() {
+        return groups;
+    }
+
+    /**
+     * Return the name of DataLab's users.
+     */
+    public Set<String> getUsers() {
+        return users;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public int compareTo(@Nonnull UserRole o) {
+        return Comparator.comparing(UserRole::getType)
+                .thenComparing(UserRole::getName)
+                .thenComparing(UserRole::getId, Comparator.nullsLast(String::compareToIgnoreCase))
+                .compare(this, o);
+    }
+
+    private ToStringHelper toStringHelper(Object self) {
+        return MoreObjects.toStringHelper(self)
+                .add("type", type)
+                .add("name", name)
+                .add("groups", groups)
+                .add("users", users);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        UserRole userRole = (UserRole) o;
+        return this.id.equals(userRole.getId()) && this.type.equals(userRole.getType()) && this.name.equals(userRole.getName());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type, name);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).toString();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/UserRoles.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/UserRoles.java
new file mode 100644
index 0000000..906e01f
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/UserRoles.java
@@ -0,0 +1,332 @@
+/*
+ * 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.datalab.backendapi.roles;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.SecurityDAO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.common.base.MoreObjects;
+import com.mongodb.client.FindIterable;
+import org.bson.Document;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Provides user roles access to features.
+ */
+public class UserRoles {
+    private static final Logger LOGGER = LoggerFactory.getLogger(UserRoles.class);
+
+    private static final String ANY_USER = "$anyuser";
+    /**
+     * Node name of groups.
+     */
+    private static final String GROUPS = "groups";
+    /**
+     * Node name of user.
+     */
+    private static final String USERS = "users";
+    private static final String PROJECT_ADMIN_ROLE_NAME = "projectAdmin";
+    private static final String ADMIN_ROLE_NAME = "admin";
+    /**
+     * Single instance of the user roles.
+     */
+    private static UserRoles userRoles = null;
+    /**
+     * List of roles.
+     */
+    private List<UserRole> roles = null;
+    private Map<String, Set<String>> userGroups;
+
+    /**
+     * Default access to features if the role is not defined.
+     */
+    private boolean defaultAccess = false;
+
+    /**
+     * Initialize user roles for all users.
+     *
+     * @param dao security DAO.
+     */
+    public static void initialize(SecurityDAO dao, boolean defaultAccess) {
+        LOGGER.trace("Loading roles from database...");
+        if (userRoles == null) {
+            userRoles = new UserRoles();
+        }
+        userRoles.load(dao, defaultAccess);
+        LOGGER.trace("New roles are	: {}", getRoles());
+    }
+
+    /**
+     * Return the list of roles for all users.
+     */
+    public static List<UserRole> getRoles() {
+        return (userRoles == null ? null : userRoles.roles());
+    }
+
+    /**
+     * Check access for user to the role.
+     *
+     * @param userInfo user info.
+     * @param type     the type of role.
+     * @param name     the name of role.
+     * @param roles
+     * @return boolean value
+     */
+    public static boolean checkAccess(UserInfo userInfo, RoleType type, String name, Collection<String> roles) {
+        return checkAccess(userInfo, type, name, true, roles);
+    }
+
+    public static boolean isProjectAdmin(UserInfo userInfo) {
+        final List<UserRole> roles = UserRoles.getRoles();
+        return roles == null || roles.stream().anyMatch(r -> PROJECT_ADMIN_ROLE_NAME.equalsIgnoreCase(r.getId()) &&
+                (userRoles.hasAccessByGroup(userInfo, userInfo.getRoles(), r.getGroups()) || userRoles.hasAccessByUserName(userInfo, r)));
+    }
+
+    public static boolean isProjectAdmin(UserInfo userInfo, Set<String> groups) {
+        final List<UserRole> roles = UserRoles.getRoles();
+        return roles == null || roles.stream().anyMatch(r -> PROJECT_ADMIN_ROLE_NAME.equalsIgnoreCase(r.getId()) &&
+                (userRoles.hasAccessByGroup(userInfo, userInfo.getRoles(), retainGroups(r.getGroups(), groups)) || userRoles.hasAccessByUserName(userInfo, r)));
+    }
+
+    public static boolean isAdmin(UserInfo userInfo) {
+        final List<UserRole> roles = UserRoles.getRoles();
+        return roles == null || roles.stream().anyMatch(r -> ADMIN_ROLE_NAME.equalsIgnoreCase(r.getId()) &&
+                (userRoles.hasAccessByGroup(userInfo, userInfo.getRoles(), r.getGroups()) || userRoles.hasAccessByUserName(userInfo, r)));
+    }
+
+    /**
+     * Check access for user to the role.
+     *
+     * @param roles
+     * @param userInfo user info.
+     * @param type     the type of role.
+     * @param name     the name of role.
+     * @return boolean value
+     */
+    public static boolean checkAccess(UserInfo userInfo, RoleType type, String name, boolean useDefault,
+                                      Collection<String> roles) {
+        return (userRoles == null || userRoles.hasAccess(userInfo, type, name, useDefault, roles));
+    }
+
+    /**
+     * Loading the user roles for all users from Mongo database.
+     *
+     * @param dao security DAO.
+     */
+    private synchronized void load(SecurityDAO dao, boolean defaultAccess) {
+        this.defaultAccess = defaultAccess;
+        try {
+            FindIterable<Document> docs = dao.getRoles();
+            roles = new ArrayList<>();
+            for (Document d : docs) {
+                Set<String> groups = getAndRemoveSet(d, GROUPS);
+                Set<String> users = getAndRemoveSet(d, USERS);
+                String id = d.getString("_id");
+                for (RoleType type : RoleType.values()) {
+                    @SuppressWarnings("unchecked")
+                    List<String> names = d.get(type.getNodeName(), ArrayList.class);
+                    if (names != null) {
+                        for (String name : names) {
+                            append(type, name, groups, users, id);
+                        }
+                    }
+                }
+            }
+            userGroups = dao.getGroups();
+        } catch (Exception e) {
+            throw new DatalabException("Cannot load roles from database. " + e.getLocalizedMessage(), e);
+        }
+    }
+
+    private synchronized List<UserRole> roles() {
+        return roles;
+    }
+
+    /**
+     * Append new role to the list if role not exists in list an return it, otherwise return
+     * existence role.
+     *
+     * @param type   type of role.
+     * @param name   the name of role.
+     * @param groups the names of external groups.
+     * @param users  the name of DataLab's users.
+     * @param id
+     * @return role.
+     */
+    private UserRole append(RoleType type, String name, Set<String> groups, Set<String> users, String id) {
+        UserRole item = new UserRole(id, type, name, groups, users);
+        synchronized (roles) {
+            int index = Collections.binarySearch(roles, item);
+            if (index < 0) {
+                index = -index;
+                if (index > roles.size()) {
+                    roles.add(item);
+                } else {
+                    roles.add(index - 1, item);
+                }
+            }
+        }
+        return item;
+    }
+
+    /**
+     * Find and return role by type and name.
+     *
+     * @param type type of role.
+     * @param name the name of role.
+     * @return list of UserRole
+     */
+    private Set<String> getGroups(RoleType type, String name) {
+        synchronized (roles) {
+            return roles
+                    .stream()
+                    .filter(r -> type == r.getType() && name.equalsIgnoreCase(r.getName()))
+                    .map(UserRole::getGroups)
+                    .flatMap(Collection::stream)
+                    .collect(Collectors.toSet());
+        }
+    }
+
+    /**
+     * Find and return a list by key from JSON document, otherwise return <b>null</b>.
+     *
+     * @param document the document.
+     * @param key      the name of node.
+     */
+    private Set<String> getAndRemoveSet(Document document, String key) {
+        Object o = document.get(key);
+        if (!(o instanceof ArrayList)) {
+            return Collections.emptySet();
+        }
+
+        @SuppressWarnings("unchecked")
+        List<String> list = (List<String>) o;
+        if (list.isEmpty()) {
+            return Collections.emptySet();
+        }
+
+        Set<String> set = new HashSet<>();
+        for (String value : list) {
+            set.add(value.toLowerCase());
+        }
+        document.remove(key);
+        return set;
+    }
+
+    /**
+     * Check access for user to the role.
+     *
+     * @param userInfo   user info.
+     * @param type       the type of role.
+     * @param name       the name of role.
+     * @param useDefault true/false
+     * @param roles
+     * @return boolean value
+     */
+    private boolean hasAccess(UserInfo userInfo, RoleType type, String name, boolean useDefault,
+                              Collection<String> roles) {
+        if (userRoles == null) {
+            return true;
+        }
+        LOGGER.trace("Check access for user {} with groups {} to {}/{}", userInfo.getName(), userInfo.getRoles(),
+                type, name);
+        Set<String> groups = getGroups(type, name);
+        if (groups == null || groups.isEmpty()) {
+            return checkDefault(useDefault);
+        }
+        if (hasAccessByGroup(userInfo, roles, groups)) {
+            return true;
+        }
+        LOGGER.trace("Access denied for user {} to {}/{}", userInfo.getName(), type, name);
+        return false;
+    }
+
+    private boolean hasAccessByGroup(UserInfo userInfo, Collection<String> userRoles, Collection<String> groups) {
+        if (groups != null) {
+            if (groups.contains(ANY_USER)) {
+                return true;
+            }
+            for (String group : userRoles) {
+                if (group != null && groups.contains(group.toLowerCase())) {
+                    LOGGER.trace("Got access by group {}", group);
+                    return true;
+                }
+            }
+
+            final Optional<String> group = groups
+                    .stream()
+                    .filter(g -> userGroups.getOrDefault(g, Collections.emptySet()).contains(userInfo.getName().toLowerCase()))
+                    .findAny();
+            if (group.isPresent()) {
+                LOGGER.trace("Got access by local group {}", group.get());
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean hasAccessByUserName(UserInfo userInfo, UserRole role) {
+        if (role.getUsers() != null &&
+                userInfo.getName() != null &&
+                (role.getUsers().contains(ANY_USER) ||
+                        role.getUsers().contains(userInfo.getName().toLowerCase()))) {
+            LOGGER.trace("Got access by name");
+            return true;
+        }
+        return false;
+    }
+
+    private boolean checkDefault(boolean useDefault) {
+        if (useDefault) {
+            LOGGER.trace("Got default access {}", defaultAccess);
+            return defaultAccess;
+        } else {
+            return false;
+        }
+    }
+
+    private static Set<String> retainGroups(Set<String> groups1, Set<String> groups2) {
+        Set<String> result = groups2
+                .stream()
+                .map(String::toLowerCase)
+                .collect(Collectors.toSet());
+        result.retainAll(groups1);
+
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(roles)
+                .addValue(roles)
+                .toString();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckApplicationQuoteScheduler.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckApplicationQuoteScheduler.java
new file mode 100644
index 0000000..b55ebcc
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckApplicationQuoteScheduler.java
@@ -0,0 +1,45 @@
+/*
+ * 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.datalab.backendapi.schedulers;
+
+import com.epam.datalab.backendapi.dao.BillingDAO;
+import com.epam.datalab.backendapi.schedulers.internal.Scheduled;
+import com.epam.datalab.backendapi.service.EnvironmentService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+@Scheduled("checkQuoteScheduler")
+@Slf4j
+public class CheckApplicationQuoteScheduler implements Job {
+    @Inject
+    private BillingDAO billingDAO;
+    @Inject
+    private EnvironmentService environmentService;
+
+    @Override
+    public void execute(JobExecutionContext context) {
+        if (billingDAO.isBillingQuoteReached()) {
+            log.warn("Stopping all environments because of reaching budget quote");
+            environmentService.stopAll();
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckInactivityScheduledJob.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckInactivityScheduledJob.java
new file mode 100644
index 0000000..e32b15f
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckInactivityScheduledJob.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.backendapi.schedulers;
+
+import com.epam.datalab.backendapi.schedulers.internal.Scheduled;
+import com.epam.datalab.backendapi.service.InactivityService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+/**
+ * There realized integration with Quartz scheduler framework and defined check cluster inactivity scheduler job which
+ * executes every time specified. If in 'self-service.yml' option 'clusterInactivityCheckerEnabled' equals 'true' then
+ * this job we be executing every time predefined in option 'clusterInactivityCheckingTimeout'. Otherwise, it will
+ * never execute.
+ */
+@Slf4j
+@Scheduled("inactivity")
+public class CheckInactivityScheduledJob implements Job {
+
+    @Inject
+    private InactivityService inactivityService;
+
+    @Override
+    public void execute(JobExecutionContext context) {
+        log.trace("Starting check inactivity job");
+        inactivityService.updateRunningResourcesLastActivity();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckProjectQuoteScheduler.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckProjectQuoteScheduler.java
new file mode 100644
index 0000000..bc16fce
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckProjectQuoteScheduler.java
@@ -0,0 +1,52 @@
+/*
+ * 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.datalab.backendapi.schedulers;
+
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.schedulers.internal.Scheduled;
+import com.epam.datalab.backendapi.service.BillingService;
+import com.epam.datalab.backendapi.service.EnvironmentService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+@Scheduled("checkProjectQuoteScheduler")
+@Slf4j
+public class CheckProjectQuoteScheduler implements Job {
+
+    @Inject
+    private BillingService billingService;
+    @Inject
+    private EnvironmentService environmentService;
+    @Inject
+    private ProjectService projectService;
+
+    @Override
+    public void execute(JobExecutionContext context) {
+        projectService.getProjects()
+                .stream()
+                .map(ProjectDTO::getName)
+                .filter(billingService::isProjectQuoteReached)
+                .peek(p -> log.debug("Stopping {} project env because of reaching user billing quote", p))
+                .forEach(environmentService::stopProjectEnvironment);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckUserQuoteScheduler.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckUserQuoteScheduler.java
new file mode 100644
index 0000000..c470763
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckUserQuoteScheduler.java
@@ -0,0 +1,49 @@
+/*
+ * 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.datalab.backendapi.schedulers;
+
+import com.epam.datalab.backendapi.dao.BillingDAO;
+import com.epam.datalab.backendapi.resources.dto.UserDTO;
+import com.epam.datalab.backendapi.schedulers.internal.Scheduled;
+import com.epam.datalab.backendapi.service.EnvironmentService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+@Scheduled("checkUserQuoteScheduler")
+@Slf4j
+public class CheckUserQuoteScheduler implements Job {
+
+    @Inject
+    private BillingDAO billingDAO;
+    @Inject
+    private EnvironmentService environmentService;
+
+    @Override
+    public void execute(JobExecutionContext context) {
+        environmentService.getUsers()
+                .stream()
+                .map(UserDTO::getName)
+                .filter(billingDAO::isUserQuoteReached)
+                .peek(u -> log.warn("Stopping {} user env because of reaching user billing quote", u))
+                .forEach(environmentService::stopEnvironmentWithServiceAccount);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/billing/BillingScheduler.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/billing/BillingScheduler.java
new file mode 100644
index 0000000..c4dc177
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/billing/BillingScheduler.java
@@ -0,0 +1,52 @@
+/*
+ * 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.datalab.backendapi.schedulers.billing;
+
+import com.epam.datalab.backendapi.schedulers.internal.Scheduled;
+import com.epam.datalab.backendapi.service.BillingService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+@Scheduled("billingScheduler")
+@Slf4j
+public class BillingScheduler implements Job {
+
+    private final BillingService billingService;
+    private final SecurityService securityService;
+
+    @Inject
+    public BillingScheduler(BillingService billingService, SecurityService securityService) {
+        this.billingService = billingService;
+        this.securityService = securityService;
+    }
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) {
+        log.info("Trying to update billing");
+        try {
+            billingService.updateRemoteBillingData(securityService.getServiceAccountInfo("admin"));
+        } catch (Exception e) {
+            log.error("Something went wrong {}", e.getMessage(), e);
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/computational/StartComputationalJob.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/computational/StartComputationalJob.java
new file mode 100644
index 0000000..a554315
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/computational/StartComputationalJob.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.backendapi.schedulers.computational;
+
+import com.epam.datalab.backendapi.schedulers.internal.Scheduled;
+import com.epam.datalab.backendapi.service.SchedulerJobService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+/**
+ * There realized integration with Quartz scheduler framework and defined start computational resource scheduler job
+ * which executes every time specified.
+ */
+@Slf4j
+@Scheduled("startComputationalScheduler")
+public class StartComputationalJob implements Job {
+
+    @Inject
+    private SchedulerJobService schedulerJobService;
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) {
+        schedulerJobService.startComputationalByScheduler();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/computational/StopComputationalJob.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/computational/StopComputationalJob.java
new file mode 100644
index 0000000..fb94af5
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/computational/StopComputationalJob.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.backendapi.schedulers.computational;
+
+import com.epam.datalab.backendapi.schedulers.internal.Scheduled;
+import com.epam.datalab.backendapi.service.SchedulerJobService;
+import com.google.inject.Inject;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+/**
+ * There realized integration with Quartz scheduler framework and defined stop computational resource scheduler job
+ * which executes every time specified.
+ */
+@Scheduled("stopComputationalScheduler")
+public class StopComputationalJob implements Job {
+
+    @Inject
+    private SchedulerJobService schedulerJobService;
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) {
+        schedulerJobService.stopComputationalByScheduler();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/computational/TerminateComputationalJob.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/computational/TerminateComputationalJob.java
new file mode 100644
index 0000000..c69b37a
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/computational/TerminateComputationalJob.java
@@ -0,0 +1,41 @@
+/*
+ * 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.datalab.backendapi.schedulers.computational;
+
+import com.epam.datalab.backendapi.schedulers.internal.Scheduled;
+import com.epam.datalab.backendapi.service.SchedulerJobService;
+import com.google.inject.Inject;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+@Scheduled("terminateComputationalScheduler")
+public class TerminateComputationalJob implements Job {
+    private final SchedulerJobService schedulerJobService;
+
+    @Inject
+    public TerminateComputationalJob(SchedulerJobService schedulerJobService) {
+        this.schedulerJobService = schedulerJobService;
+    }
+
+    @Override
+    public void execute(JobExecutionContext context) {
+        schedulerJobService.terminateComputationalByScheduler();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/endpoint/CheckEndpointStatusScheduler.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/endpoint/CheckEndpointStatusScheduler.java
new file mode 100644
index 0000000..f88050a
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/endpoint/CheckEndpointStatusScheduler.java
@@ -0,0 +1,66 @@
+/*
+ * 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.datalab.backendapi.schedulers.endpoint;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.schedulers.internal.Scheduled;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+@Scheduled("checkEndpointStatusScheduler")
+@Slf4j
+public class CheckEndpointStatusScheduler implements Job {
+
+    @Inject
+    private EndpointService endpointService;
+    @Inject
+    private SecurityService securityService;
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) {
+        UserInfo serviceUser = securityService.getServiceAccountInfo("admin");
+        endpointService.getEndpoints().stream()
+                .filter(endpoint -> checkUrlWithStatus(serviceUser, endpoint))
+                .forEach(this::changeStatusToOpposite);
+    }
+
+    private boolean checkUrlWithStatus(UserInfo serviceUser, EndpointDTO endpoint) {
+        try {
+            endpointService.checkUrl(serviceUser, endpoint.getUrl());
+        } catch (Exception e) {
+            log.warn("Failed connecting to endpoint {}, url: '{}'. {}", endpoint.getName(), endpoint.getUrl(), e.getMessage(), e);
+            return endpoint.getStatus() == EndpointDTO.EndpointStatus.ACTIVE;
+        }
+        return endpoint.getStatus() == EndpointDTO.EndpointStatus.INACTIVE;
+    }
+
+    private void changeStatusToOpposite(EndpointDTO endpoint) {
+        if (endpoint.getStatus() == EndpointDTO.EndpointStatus.ACTIVE) {
+            endpointService.updateEndpointStatus(endpoint.getName(), EndpointDTO.EndpointStatus.INACTIVE);
+        } else {
+            endpointService.updateEndpointStatus(endpoint.getName(), EndpointDTO.EndpointStatus.ACTIVE);
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/exploratory/StartExploratoryJob.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/exploratory/StartExploratoryJob.java
new file mode 100644
index 0000000..a3c732b
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/exploratory/StartExploratoryJob.java
@@ -0,0 +1,45 @@
+/*
+ * 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.datalab.backendapi.schedulers.exploratory;
+
+import com.epam.datalab.backendapi.schedulers.internal.Scheduled;
+import com.epam.datalab.backendapi.service.SchedulerJobService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+/**
+ * There realized integration with Quartz scheduler framework and defined start exploratory scheduler job which
+ * executes every time specified.
+ */
+@Slf4j
+@Scheduled("startExploratoryScheduler")
+public class StartExploratoryJob implements Job {
+
+    @Inject
+    private SchedulerJobService schedulerJobService;
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) {
+        schedulerJobService.startExploratoryByScheduler();
+    }
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/exploratory/StopExploratoryJob.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/exploratory/StopExploratoryJob.java
new file mode 100644
index 0000000..f3fdb63
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/exploratory/StopExploratoryJob.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.backendapi.schedulers.exploratory;
+
+import com.epam.datalab.backendapi.schedulers.internal.Scheduled;
+import com.epam.datalab.backendapi.service.SchedulerJobService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+/**
+ * There realized integration with Quartz scheduler framework and defined stop exploratory scheduler job which
+ * executes every time specified.
+ */
+@Slf4j
+@Scheduled("stopExploratoryScheduler")
+public class StopExploratoryJob implements Job {
+
+    @Inject
+    private SchedulerJobService schedulerJobService;
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) {
+        schedulerJobService.stopExploratoryByScheduler();
+    }
+
+}
+
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/internal/ManagedScheduler.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/internal/ManagedScheduler.java
new file mode 100644
index 0000000..2c50768
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/internal/ManagedScheduler.java
@@ -0,0 +1,115 @@
+/*
+ * 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.datalab.backendapi.schedulers.internal;
+
+import com.epam.datalab.backendapi.SelfServiceApplication;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.domain.SchedulerConfigurationData;
+import com.epam.datalab.exceptions.DatalabException;
+import com.fiestacabin.dropwizard.quartz.GuiceJobFactory;
+import com.google.inject.Inject;
+import io.dropwizard.lifecycle.Managed;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.CronScheduleBuilder;
+import org.quartz.Job;
+import org.quartz.JobDetail;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.TriggerKey;
+import org.reflections.Reflections;
+import org.reflections.scanners.SubTypesScanner;
+
+import java.util.Optional;
+
+import static org.quartz.JobBuilder.newJob;
+import static org.quartz.TriggerBuilder.newTrigger;
+
+@Slf4j
+public class ManagedScheduler implements Managed {
+	private final Scheduler scheduler;
+	private final GuiceJobFactory jobFactory;
+	private final SelfServiceApplicationConfiguration config;
+
+	@Inject
+	public ManagedScheduler(Scheduler scheduler, GuiceJobFactory jobFactory,
+							SelfServiceApplicationConfiguration config) {
+		this.scheduler = scheduler;
+		this.jobFactory = jobFactory;
+		this.config = config;
+	}
+
+	@Override
+	public void start() throws Exception {
+		scheduler.setJobFactory(jobFactory);
+		scheduler.start();
+
+		new Reflections(SelfServiceApplication.class.getPackage().getName(), new SubTypesScanner())
+				.getSubTypesOf(Job.class)
+				.forEach(scheduledClass ->
+						Optional.ofNullable(scheduledClass.getAnnotation(Scheduled.class))
+								.filter(this::triggerNotExist)
+								.ifPresent(scheduleAnn -> schedule(scheduledClass, scheduleAnn)));
+
+	}
+
+	@Override
+	public void stop() throws Exception {
+		scheduler.shutdown();
+	}
+
+	private Trigger getTrigger(SchedulerConfigurationData schedulerConfig, String schedulerName) {
+		return newTrigger()
+				.withIdentity(schedulerName)
+				.withSchedule(CronScheduleBuilder.cronSchedule(schedulerConfig.getCron()))
+				.startNow()
+				.build();
+	}
+
+	private void schedule(Class<? extends Job> scheduledClass, Scheduled scheduleAnn) {
+		final String schedulerName = scheduleAnn.value();
+		final SchedulerConfigurationData schedulerConfig =
+				Optional.ofNullable(config.getSchedulers().get(schedulerName)).orElseThrow(() -> new IllegalStateException(
+						"There is no configuration provided for scheduler with name " + schedulerName));
+		if (schedulerConfig.isEnabled()) {
+			scheduleJob(newJob(scheduledClass).build(), schedulerConfig, scheduleAnn.value());
+		}
+	}
+
+	private void scheduleJob(JobDetail job, SchedulerConfigurationData schedulerConfig, String schedulerName) {
+		try {
+			final Trigger trigger = getTrigger(schedulerConfig, schedulerName);
+			scheduler.scheduleJob(job, trigger);
+			log.info("Scheduled job {} with trigger {}", job, trigger);
+		} catch (SchedulerException e) {
+			log.error("Can't schedule job due to: {}", e.getMessage());
+			throw new DatalabException("Can't schedule job due to: " + e.getMessage(), e);
+		}
+	}
+
+	private boolean triggerNotExist(Scheduled scheduled) {
+		try {
+			return !scheduler.checkExists(new TriggerKey(scheduled.value()));
+		} catch (SchedulerException e) {
+			log.error("Can not check if trigger exist due to: {}", e.getMessage());
+			throw new DatalabException("Can not check if trigger exist due to: {}" + e.getMessage(), e);
+		}
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/internal/Scheduled.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/internal/Scheduled.java
new file mode 100644
index 0000000..8900f44
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/internal/Scheduled.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.datalab.backendapi.schedulers.internal;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation is used as alternative to {@link com.fiestacabin.dropwizard.quartz.Scheduled}
+ * and allow to use scheduler configuration from application config
+ * }
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Scheduled {
+    /**
+     * @return scheduler name
+     */
+    String value();
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/AccessKeyService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/AccessKeyService.java
new file mode 100644
index 0000000..41f9db8
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/AccessKeyService.java
@@ -0,0 +1,28 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.KeysDTO;
+
+@FunctionalInterface
+public interface AccessKeyService {
+    KeysDTO generateKeys(UserInfo userInfo);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ApplicationSettingService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ApplicationSettingService.java
new file mode 100644
index 0000000..7d4bf0e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ApplicationSettingService.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.datalab.backendapi.service;
+
+import java.util.Map;
+
+public interface ApplicationSettingService {
+
+    void removeMaxBudget();
+
+    void setMaxBudget(Long maxBudget);
+
+    Map<String, Object> getSettings();
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ApplicationSettingServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ApplicationSettingServiceImpl.java
new file mode 100644
index 0000000..1e28bc1
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ApplicationSettingServiceImpl.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.backendapi.dao.MongoSetting;
+import com.epam.datalab.backendapi.dao.SettingsDAO;
+import com.google.inject.Inject;
+
+import java.util.Map;
+
+public class ApplicationSettingServiceImpl implements ApplicationSettingService {
+    @Inject
+    private SettingsDAO settingsDAO;
+
+    @Override
+    public void removeMaxBudget() {
+        settingsDAO.removeSetting(MongoSetting.CONF_MAX_BUDGET);
+    }
+
+    @Override
+    public void setMaxBudget(Long maxBudget) {
+        settingsDAO.setMaxBudget(maxBudget);
+    }
+
+    @Override
+    public Map<String, Object> getSettings() {
+        return settingsDAO.getSettings();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/AuditService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/AuditService.java
new file mode 100644
index 0000000..6dc4ab5
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/AuditService.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.backendapi.domain.AuditCreateDTO;
+import com.epam.datalab.backendapi.domain.AuditDTO;
+import com.epam.datalab.backendapi.domain.AuditPaginationDTO;
+
+import java.util.List;
+
+public interface AuditService {
+    void save(AuditDTO audit);
+
+    void save(String user, AuditCreateDTO audit);
+
+    List<AuditPaginationDTO> getAudit(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd, int pageNumber, int pageSize);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/BackupService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/BackupService.java
new file mode 100644
index 0000000..aec15d0
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/BackupService.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.BackupInfoRecord;
+import com.epam.datalab.dto.backup.EnvBackupDTO;
+import com.epam.datalab.dto.backup.EnvBackupStatus;
+
+import java.util.List;
+
+public interface BackupService {
+    String createBackup(EnvBackupDTO dto, UserInfo userInfo);
+
+    void updateStatus(EnvBackupDTO dto, String user, EnvBackupStatus status);
+
+    List<BackupInfoRecord> getBackups(String userName);
+
+    BackupInfoRecord getBackup(String userName, String id);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/BillingService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/BillingService.java
new file mode 100644
index 0000000..d0c0188
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/BillingService.java
@@ -0,0 +1,43 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.BillingReport;
+import com.epam.datalab.backendapi.resources.dto.BillingFilter;
+import com.epam.datalab.backendapi.resources.dto.QuotaUsageDTO;
+
+import java.util.List;
+
+public interface BillingService {
+    BillingReport getBillingReport(UserInfo userInfo, BillingFilter filter);
+
+    String downloadReport(UserInfo userInfo, BillingFilter filter);
+
+    BillingReport getExploratoryBillingData(String project, String endpoint, String exploratoryName, List<String> compNames);
+
+    void updateRemoteBillingData(UserInfo userInfo);
+
+    QuotaUsageDTO getQuotas(UserInfo userInfo);
+
+    boolean isProjectQuoteReached(String project);
+
+    int getBillingProjectQuoteUsed(String project);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/BucketService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/BucketService.java
new file mode 100644
index 0000000..1ed737c
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/BucketService.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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.dto.bucket.BucketDTO;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.util.List;
+
+public interface BucketService {
+    List<BucketDTO> getObjects(UserInfo userInfo, String bucket, String endpoint);
+
+    void uploadObject(UserInfo userInfo, String bucket, String object, String endpoint, InputStream inputStream, String contentType, long fileSize, String auditInfo);
+
+    void uploadFolder(UserInfo userInfo, String bucket, String folder, String endpoint, String auditInfo);
+
+    void downloadObject(UserInfo userInfo, String bucket, String object, String endpoint, HttpServletResponse resp, String auditInfo);
+
+    void deleteObjects(UserInfo userInfo, String bucket, List<String> objects, String endpoint, String auditInfo);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ComputationalService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ComputationalService.java
new file mode 100644
index 0000000..a930d9f
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ComputationalService.java
@@ -0,0 +1,74 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.ComputationalCreateFormDTO;
+import com.epam.datalab.backendapi.resources.dto.ComputationalTemplatesDTO;
+import com.epam.datalab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface ComputationalService {
+    ComputationalTemplatesDTO getComputationalNamesAndTemplates(UserInfo user, String project, String endpoint);
+
+    /**
+     * Asynchronously triggers creation of Spark cluster
+     *
+     * @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, String resourceName, SparkStandaloneClusterCreateForm form, String project, 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 computationalName computational name
+     * @param auditInfo         additional info for audit
+     */
+    void terminateComputational(UserInfo userInfo, String resourceCreator, String project, String exploratoryName, String computationalName, String auditInfo);
+
+    boolean createDataEngineService(UserInfo userInfo, String resourceName, ComputationalCreateFormDTO formDTO, UserComputationalResource
+            computationalResource, String project, String auditInfo);
+
+    void stopSparkCluster(UserInfo userInfo, String resourceCreator, String project, String exploratoryName, String computationalName, String auditInfo);
+
+    void startSparkCluster(UserInfo userInfo, String exploratoryName, String computationalName, String project, String auditInfo);
+
+    void updateSparkClusterConfig(UserInfo userInfo, String project, String exploratoryName, String computationalName,
+                                  List<ClusterConfig> config, String auditInfo);
+
+    Optional<UserComputationalResource> getComputationalResource(String user, String project, String exploratoryName,
+                                                                 String computationalName);
+
+    List<ClusterConfig> getClusterConfig(UserInfo userInfo, String project, String exploratoryName, String computationalName);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/EndpointService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/EndpointService.java
new file mode 100644
index 0000000..41afa18
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/EndpointService.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.EndpointResourcesDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.cloud.CloudProvider;
+
+import java.util.List;
+
+public interface EndpointService {
+    List<EndpointDTO> getEndpoints();
+
+    List<EndpointDTO> getEndpointsWithStatus(EndpointDTO.EndpointStatus status);
+
+    EndpointResourcesDTO getEndpointResources(String endpoint);
+
+    EndpointDTO get(String name);
+
+    void create(UserInfo userInfo, String resourceName, EndpointDTO endpointDTO);
+
+    void updateEndpointStatus(String name, EndpointDTO.EndpointStatus status);
+
+    void remove(UserInfo userInfo, String name);
+
+    void removeEndpointInAllProjects(UserInfo userInfo, String endpointName, List<ProjectDTO> projects);
+
+    CloudProvider checkUrl(UserInfo userInfo, String url);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/EnvironmentService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/EnvironmentService.java
new file mode 100644
index 0000000..549a405
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/EnvironmentService.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.UserDTO;
+import com.epam.datalab.backendapi.resources.dto.UserResourceInfo;
+
+import java.util.List;
+
+public interface EnvironmentService {
+    List<UserDTO> getUsers();
+
+    List<UserResourceInfo> getAllEnv(UserInfo user);
+
+    void stopAll();
+
+    void stopEnvironmentWithServiceAccount(String user);
+
+    void stopProjectEnvironment(String project);
+
+    void stopExploratory(UserInfo userInfo, String user, String project, String exploratoryName);
+
+    void stopComputational(UserInfo userInfo, String user, String project, String exploratoryName, String computationalName);
+
+    void terminateExploratory(UserInfo userInfo, String user, String project, String exploratoryName);
+
+    void terminateComputational(UserInfo userInfo, String user, String project, String exploratoryName, String computationalName);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ExploratoryService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ExploratoryService.java
new file mode 100644
index 0000000..f16bcfc
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ExploratoryService.java
@@ -0,0 +1,62 @@
+/*
+ * 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.datalab.backendapi.service;
+
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.resources.dto.ExploratoryCreatePopUp;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.model.exploratory.Exploratory;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+public interface ExploratoryService {
+
+    String start(UserInfo userInfo, String exploratoryName, String project, String auditInfo);
+
+    String stop(UserInfo userInfo, String resourceCreator, String project, String exploratoryName, String auditInfo);
+
+    String terminate(UserInfo userInfo, String resourceCreator, String project, String exploratoryName, String auditInfo);
+
+    String create(UserInfo userInfo, Exploratory exploratory, String project, String exploratoryName);
+
+    void updateProjectExploratoryStatuses(UserInfo userInfo, String project, String endpoint, UserInstanceStatus status);
+
+    void updateProjectExploratoryStatuses(String project, String endpoint, UserInstanceStatus status);
+
+    void updateClusterConfig(UserInfo userInfo, String project, String exploratoryName, List<ClusterConfig> config);
+
+    Optional<UserInstanceDTO> getUserInstance(String user, String project, String exploratoryName);
+
+    Optional<UserInstanceDTO> getUserInstance(String user, String project, String exploratoryName, boolean includeCompResources);
+
+    List<UserInstanceDTO> findAll();
+
+    List<UserInstanceDTO> findAll(Set<ProjectDTO> projects);
+
+    List<ClusterConfig> getClusterConfig(UserInfo user, String project, String exploratoryName);
+
+    ExploratoryCreatePopUp getUserInstances(UserInfo user);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ExternalLibraryService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ExternalLibraryService.java
new file mode 100644
index 0000000..768f3a5
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ExternalLibraryService.java
@@ -0,0 +1,28 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.backendapi.resources.dto.LibraryDTO;
+
+@FunctionalInterface
+public interface ExternalLibraryService {
+
+    LibraryDTO getLibrary(String groupId, String artifactId, String version);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/GitCredentialService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/GitCredentialService.java
new file mode 100644
index 0000000..b4294d5
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/GitCredentialService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsDTO;
+
+public interface GitCredentialService {
+    void updateGitCredentials(UserInfo userInfo, ExploratoryGitCredsDTO dto);
+
+    ExploratoryGitCredsDTO getGitCredentials(String user);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/GuacamoleService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/GuacamoleService.java
new file mode 100644
index 0000000..2b19703
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/GuacamoleService.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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import org.apache.guacamole.net.GuacamoleTunnel;
+
+@FunctionalInterface
+public interface GuacamoleService {
+
+    GuacamoleTunnel getTunnel(UserInfo userInfo, String host, String endpoint);
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ImageExploratoryService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ImageExploratoryService.java
new file mode 100644
index 0000000..fae72a3
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ImageExploratoryService.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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.model.exploratory.Image;
+
+import java.util.List;
+
+public interface ImageExploratoryService {
+
+    String createImage(UserInfo user, String project, String exploratoryName, String imageName, String imageDescription, String info);
+
+    void finishImageCreate(Image image, String exploratoryName, String newNotebookIp);
+
+    List<ImageInfoRecord> getNotFailedImages(String user, String dockerImage, String project, String endpoint);
+
+    ImageInfoRecord getImage(String user, String name, String project, String endpoint);
+
+    List<ImageInfoRecord> getImagesForProject(String project);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/InactivityService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/InactivityService.java
new file mode 100644
index 0000000..a0586b2
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/InactivityService.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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+
+import java.time.LocalDateTime;
+
+public interface InactivityService {
+
+    void updateRunningResourcesLastActivity();
+
+    void updateLastActivityForExploratory(UserInfo userInfo, String exploratoryName, LocalDateTime lastActivity);
+
+    void updateLastActivityForComputational(UserInfo userInfo, String project, String exploratoryName,
+                                            String computationalName, LocalDateTime lastActivity);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/InfrastructureInfoService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/InfrastructureInfoService.java
new file mode 100644
index 0000000..c64b99e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/InfrastructureInfoService.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.HealthStatusPageDTO;
+import com.epam.datalab.backendapi.resources.dto.ProjectInfrastructureInfo;
+import com.epam.datalab.dto.InfrastructureMetaInfoDTO;
+
+import java.util.List;
+
+public interface InfrastructureInfoService {
+    List<ProjectInfrastructureInfo> getUserResources(UserInfo user);
+
+    HealthStatusPageDTO getHeathStatus(UserInfo user);
+
+    InfrastructureMetaInfoDTO getInfrastructureMetaInfo();
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/InfrastructureTemplateService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/InfrastructureTemplateService.java
new file mode 100644
index 0000000..6532c6d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/InfrastructureTemplateService.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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.dto.base.computational.FullComputationalTemplate;
+import com.epam.datalab.dto.imagemetadata.ExploratoryMetadataDTO;
+
+import java.util.List;
+
+public interface InfrastructureTemplateService {
+    List<ExploratoryMetadataDTO> getExploratoryTemplates(UserInfo user, String project, String endpoint);
+
+    List<FullComputationalTemplate> getComputationalTemplates(UserInfo user, String project, String endpoint);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/KeycloakService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/KeycloakService.java
new file mode 100644
index 0000000..cb9cf0a
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/KeycloakService.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.datalab.backendapi.service;
+
+import org.keycloak.representations.AccessTokenResponse;
+
+public interface KeycloakService {
+    AccessTokenResponse getToken(String code);
+
+    AccessTokenResponse refreshToken(String refreshToken);
+
+    AccessTokenResponse generateAccessToken(String refreshToken);
+
+    AccessTokenResponse generateServiceAccountToken();
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/KeycloakServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/KeycloakServiceImpl.java
new file mode 100644
index 0000000..a3672ea
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/KeycloakServiceImpl.java
@@ -0,0 +1,111 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.SecurityDAO;
+import com.epam.datalab.backendapi.util.KeycloakUtil;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.inject.Inject;
+import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
+import lombok.extern.slf4j.Slf4j;
+import org.glassfish.jersey.internal.util.Base64;
+import org.keycloak.representations.AccessTokenResponse;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+@Slf4j
+public class KeycloakServiceImpl implements KeycloakService {
+
+    private static final String URI = "/realms/%s/protocol/openid-connect/token";
+    private static final String GRANT_TYPE = "grant_type";
+    private final Client httpClient;
+    private final KeycloakConfiguration conf;
+    private final SecurityDAO securityDAO;
+    private final String redirectUri;
+
+    @Inject
+    public KeycloakServiceImpl(Client httpClient, SelfServiceApplicationConfiguration conf, SecurityDAO securityDAO) {
+        this.httpClient = httpClient;
+        this.conf = conf.getKeycloakConfiguration();
+        this.securityDAO = securityDAO;
+        this.redirectUri = conf.getKeycloakConfiguration().getRedirectUri();
+    }
+
+    @Override
+    public AccessTokenResponse getToken(String code) {
+        return requestToken(accessTokenRequestForm(code));
+    }
+
+    @Override
+    public AccessTokenResponse refreshToken(String refreshToken) {
+        return requestToken(refreshTokenRequestForm(refreshToken));
+    }
+
+    @Override
+    public AccessTokenResponse generateAccessToken(String refreshToken) {
+        AccessTokenResponse tokenResponse = refreshToken(refreshToken);
+        final String username = KeycloakUtil.parseToken(tokenResponse.getToken()).getPreferredUsername();
+        securityDAO.updateUser(username, tokenResponse);
+        return tokenResponse;
+    }
+
+    @Override
+    public AccessTokenResponse generateServiceAccountToken() {
+        return requestToken(serviceAccountRequestForm());
+    }
+
+    private AccessTokenResponse requestToken(Form requestForm) {
+        final String credentials = Base64.encodeAsString(String.join(":", conf.getResource(),
+                String.valueOf(conf.getCredentials().get("secret"))));
+        final Response response =
+                httpClient.target(conf.getAuthServerUrl() + String.format(URI, conf.getRealm())).request()
+                        .header(HttpHeaders.AUTHORIZATION, "Basic " + credentials)
+                        .post(Entity.form(requestForm));
+        if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) {
+
+            log.error("Error getting token:code {}, body {}", response.getStatus(), response.readEntity(String.class));
+            throw new DatalabException("can not get token");
+        }
+        return response.readEntity(AccessTokenResponse.class);
+    }
+
+    private Form accessTokenRequestForm(String code) {
+        return new Form()
+                .param(GRANT_TYPE, "authorization_code")
+                .param("code", code)
+                .param("redirect_uri", redirectUri);
+    }
+
+    private Form refreshTokenRequestForm(String refreshToken) {
+        return new Form()
+                .param(GRANT_TYPE, "refresh_token")
+                .param("refresh_token", refreshToken);
+    }
+
+    private Form serviceAccountRequestForm() {
+        return new Form()
+                .param(GRANT_TYPE, "client_credentials");
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/LibraryService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/LibraryService.java
new file mode 100644
index 0000000..c212827
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/LibraryService.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.LibInfoRecord;
+import com.epam.datalab.dto.exploratory.LibInstallDTO;
+import org.bson.Document;
+
+import java.util.List;
+
+public interface LibraryService {
+    List<Document> getLibs(String user, String project, String exploratoryName, String computationalName);
+
+    List<LibInfoRecord> getLibInfo(String user, String project, String exploratoryName);
+
+    String installComputationalLibs(UserInfo userInfo, String project, String exploratoryName, String computationalName,
+                                    List<LibInstallDTO> libs, String auditInfo);
+
+    String installExploratoryLibs(UserInfo userInfo, String project, String exploratoryName, List<LibInstallDTO> libs, String auditInfo);
+
+    List<String> getExploratoryLibGroups(UserInfo userInfo, String projectName, String exploratoryName);
+
+    List<String> getComputeLibGroups();
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ProjectService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ProjectService.java
new file mode 100644
index 0000000..46ceaa7
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ProjectService.java
@@ -0,0 +1,61 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.UpdateProjectBudgetDTO;
+import com.epam.datalab.backendapi.domain.UpdateProjectDTO;
+
+import java.util.List;
+
+public interface ProjectService {
+    List<ProjectDTO> getProjects();
+
+    List<ProjectDTO> getProjects(UserInfo user);
+
+    List<ProjectDTO> getUserProjects(UserInfo userInfo, boolean active);
+
+    List<ProjectDTO> getProjectsByEndpoint(String endpointName);
+
+    void create(UserInfo userInfo, ProjectDTO projectDTO, String resourceName);
+
+    ProjectDTO get(String name);
+
+    void terminateEndpoint(UserInfo userInfo, String endpoint, String name);
+
+    void terminateEndpoint(UserInfo userInfo, List<String> endpoints, String name);
+
+    void start(UserInfo userInfo, String endpoint, String name);
+
+    void start(UserInfo userInfo, List<String> endpoints, String name);
+
+    void stop(UserInfo userInfo, String endpoint, String name, String auditInfo);
+
+    void stopWithResources(UserInfo userInfo, List<String> endpoints, String projectName);
+
+    void update(UserInfo userInfo, UpdateProjectDTO projectDTO, String projectName);
+
+    void updateBudget(UserInfo userInfo, List<UpdateProjectBudgetDTO> projects);
+
+    boolean isAnyProjectAssigned(UserInfo userInfo);
+
+    boolean checkExploratoriesAndComputationalProgress(String projectName, List<String> endpoints);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ReuploadKeyService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ReuploadKeyService.java
new file mode 100644
index 0000000..36370b3
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ReuploadKeyService.java
@@ -0,0 +1,28 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyStatusDTO;
+
+@FunctionalInterface
+public interface ReuploadKeyService {
+
+    void updateResourceData(ReuploadKeyStatusDTO dto);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/SchedulerJobService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/SchedulerJobService.java
new file mode 100644
index 0000000..0f68320
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/SchedulerJobService.java
@@ -0,0 +1,92 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.model.scheduler.SchedulerJobData;
+
+import java.util.List;
+
+public interface SchedulerJobService {
+    /**
+     * Pulls out scheduler job data for user <code>user<code/> and his exploratory <code>exploratoryName<code/>
+     *
+     * @param user            user's name
+     * @param project         project name
+     * @param exploratoryName name of exploratory resource
+     * @return dto object
+     */
+    SchedulerJobDTO fetchSchedulerJobForUserAndExploratory(String user, String project, String exploratoryName);
+
+    /**
+     * Pulls out scheduler job data for computational resource <code>computationalName<code/> affiliated with
+     * user <code>user<code/> and his exploratory <code>exploratoryName<code/>
+     *
+     * @param user              user's name
+     * @param project           project name
+     * @param exploratoryName   name of exploratory resource
+     * @param computationalName name of computational resource
+     * @return dto object
+     */
+    SchedulerJobDTO fetchSchedulerJobForComputationalResource(String user, String project, String exploratoryName,
+                                                              String computationalName);
+
+    /**
+     * Updates scheduler job data for user <code>user<code/> and his exploratory <code>exploratoryName<code/>
+     *
+     * @param user            user's name
+     * @param project         project name
+     * @param exploratoryName name of exploratory resource
+     * @param dto             scheduler job data
+     */
+    void updateExploratorySchedulerData(UserInfo user, String project, String exploratoryName, SchedulerJobDTO dto);
+
+    /**
+     * Updates scheduler job data for computational resource <code>computationalName<code/> affiliated with
+     * user <code>user<code/> and his exploratory <code>exploratoryName<code/>
+     *
+     * @param user              user's name
+     * @param project           project name
+     * @param exploratoryName   name of exploratory resource
+     * @param computationalName name of computational resource
+     * @param dto               scheduler job data
+     */
+    void updateComputationalSchedulerData(UserInfo user, String project, String exploratoryName,
+                                          String computationalName, SchedulerJobDTO dto);
+
+    void stopComputationalByScheduler();
+
+    void stopExploratoryByScheduler();
+
+    void startExploratoryByScheduler();
+
+    void startComputationalByScheduler();
+
+    void terminateExploratoryByScheduler();
+
+    void terminateComputationalByScheduler();
+
+    void removeScheduler(String user, String exploratoryName);
+
+    void removeScheduler(String user, String exploratoryName, String computationalName);
+
+    List<SchedulerJobData> getActiveSchedulers(String user, long timeOffset);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/SecurityService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/SecurityService.java
new file mode 100644
index 0000000..dd969cf
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/SecurityService.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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+
+public interface SecurityService {
+    UserInfo getUserInfo(String code);
+
+    UserInfo getUserInfoOffline(String username);
+
+    UserInfo getServiceAccountInfo(String username);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/SecurityServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/SecurityServiceImpl.java
new file mode 100644
index 0000000..cde3edf
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/SecurityServiceImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.SecurityDAO;
+import com.epam.datalab.backendapi.domain.AuditActionEnum;
+import com.epam.datalab.backendapi.domain.AuditDTO;
+import com.epam.datalab.backendapi.util.KeycloakUtil;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.inject.Inject;
+import org.keycloak.representations.AccessTokenResponse;
+
+public class SecurityServiceImpl implements SecurityService {
+    private final KeycloakService keycloakService;
+    private final SecurityDAO securityDAO;
+    private final AuditService auditService;
+
+    @Inject
+    public SecurityServiceImpl(KeycloakService keycloakService, SecurityDAO securityDAO, AuditService auditService) {
+        this.keycloakService = keycloakService;
+        this.securityDAO = securityDAO;
+        this.auditService = auditService;
+    }
+
+    @Override
+    public UserInfo getUserInfo(String code) {
+        final AccessTokenResponse token = keycloakService.getToken(code);
+        final String username = KeycloakUtil.parseToken(token.getToken()).getPreferredUsername();
+        securityDAO.saveUser(username, token);
+        UserInfo userInfo = new UserInfo(username, token.getToken());
+        userInfo.setRefreshToken(token.getRefreshToken());
+        saveLogInAudit(username);
+        return userInfo;
+    }
+
+    @Override
+    public UserInfo getUserInfoOffline(String username) {
+        return securityDAO.getTokenResponse(username)
+                .map(AccessTokenResponse::getRefreshToken)
+                .map(keycloakService::refreshToken)
+                .map(accessTokenResponse -> new UserInfo(KeycloakUtil.parseToken(accessTokenResponse.getToken()).getPreferredUsername(),
+                        accessTokenResponse.getToken()))
+                .orElseThrow(() -> new DatalabException("Can not find token for user " + username));
+    }
+
+    @Override
+    public UserInfo getServiceAccountInfo(String username) {
+        AccessTokenResponse accessTokenResponse = keycloakService.generateServiceAccountToken();
+        return new UserInfo(username, accessTokenResponse.getToken());
+    }
+
+    private void saveLogInAudit(String username) {
+        AuditDTO auditDTO = AuditDTO.builder()
+                .user(username)
+                .action(AuditActionEnum.LOG_IN)
+                .build();
+        auditService.save(auditDTO);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/SystemInfoService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/SystemInfoService.java
new file mode 100644
index 0000000..b0e58ad
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/SystemInfoService.java
@@ -0,0 +1,27 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.backendapi.resources.dto.SystemInfoDto;
+
+@FunctionalInterface
+public interface SystemInfoService {
+
+    SystemInfoDto getSystemInfo();
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/TagService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/TagService.java
new file mode 100644
index 0000000..e003e02
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/TagService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+
+import java.util.Map;
+
+@FunctionalInterface
+public interface TagService {
+    Map<String, String> getResourceTags(UserInfo userInfo, String endpoint, String project, String customTag);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/TagServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/TagServiceImpl.java
new file mode 100644
index 0000000..1990dfa
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/TagServiceImpl.java
@@ -0,0 +1,41 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.google.inject.Singleton;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+@Singleton
+public class TagServiceImpl implements TagService {
+
+    @Override
+    public Map<String, String> getResourceTags(UserInfo userInfo, String endpoint, String project, String customTag) {
+        Map<String, String> tags = new HashMap<>();
+        tags.put("user_tag", userInfo.getName());
+        tags.put("endpoint_tag", endpoint);
+        tags.put("project_tag", project);
+        Optional.ofNullable(customTag).ifPresent(t -> tags.put("custom_tag", t));
+        return tags;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserGroupService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserGroupService.java
new file mode 100644
index 0000000..c95d4ad
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserGroupService.java
@@ -0,0 +1,37 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.UserGroupDto;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public interface UserGroupService {
+
+    void createGroup(UserInfo userInfo, String group, Set<String> roleIds, Set<String> users);
+
+    void updateGroup(UserInfo user, String group, Map<String, String> roles, Set<String> users);
+
+    void removeGroup(UserInfo userInfo, String groupId);
+
+    List<UserGroupDto> getAggregatedRolesByGroup(UserInfo user);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserRoleService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserRoleService.java
new file mode 100644
index 0000000..87c8487
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserRoleService.java
@@ -0,0 +1,34 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.backendapi.resources.dto.UserRoleDto;
+
+import java.util.List;
+
+public interface UserRoleService {
+
+    List<UserRoleDto> getUserRoles();
+
+    void createRole(UserRoleDto dto);
+
+    void updateRole(UserRoleDto dto);
+
+    void removeRole(String roleId);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserRoleServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserRoleServiceImpl.java
new file mode 100644
index 0000000..2994a78
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserRoleServiceImpl.java
@@ -0,0 +1,63 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.backendapi.dao.UserRoleDAO;
+import com.epam.datalab.backendapi.resources.dto.UserRoleDto;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+@Singleton
+public class UserRoleServiceImpl implements UserRoleService {
+    private static final String ROLE_NOT_FOUND_MSG = "Any of role : %s were not found";
+
+    @Inject
+    private UserRoleDAO userRoleDao;
+
+    @Override
+    public List<UserRoleDto> getUserRoles() {
+        return userRoleDao.findAll();
+    }
+
+    @Override
+    public void createRole(UserRoleDto dto) {
+        userRoleDao.insert(dto);
+    }
+
+    @Override
+    public void updateRole(UserRoleDto dto) {
+        checkAnyRoleFound(Collections.singleton(dto.getId()), userRoleDao.update(dto));
+    }
+
+    @Override
+    public void removeRole(String roleId) {
+        userRoleDao.remove(roleId);
+    }
+
+    private void checkAnyRoleFound(Set<String> roleIds, boolean anyRoleFound) {
+        if (!anyRoleFound) {
+            throw new ResourceNotFoundException(String.format(ROLE_NOT_FOUND_MSG, roleIds));
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserSettingService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserSettingService.java
new file mode 100644
index 0000000..529e7c4
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserSettingService.java
@@ -0,0 +1,35 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.UserDTO;
+
+import java.util.List;
+
+public interface UserSettingService {
+
+    void saveUISettings(UserInfo userInfo, String settings);
+
+    String getUISettings(UserInfo userInfo);
+
+    void updateUsersBudget(List<UserDTO> budgets);
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserSettingServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserSettingServiceImpl.java
new file mode 100644
index 0000000..20be82e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/UserSettingServiceImpl.java
@@ -0,0 +1,48 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.UserSettingsDAO;
+import com.epam.datalab.backendapi.resources.dto.UserDTO;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import java.util.List;
+
+@Singleton
+public class UserSettingServiceImpl implements UserSettingService {
+    @Inject
+    private UserSettingsDAO settingsDAO;
+
+    @Override
+    public void saveUISettings(UserInfo userInfo, String settings) {
+        settingsDAO.setUISettings(userInfo, settings);
+    }
+
+    @Override
+    public String getUISettings(UserInfo userInfo) {
+        return settingsDAO.getUISettings(userInfo);
+    }
+
+    @Override
+    public void updateUsersBudget(List<UserDTO> budgets) {
+        budgets.forEach(settingsDAO::updateBudget);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/AccessKeyServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/AccessKeyServiceImpl.java
new file mode 100644
index 0000000..d9c119e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/AccessKeyServiceImpl.java
@@ -0,0 +1,59 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.resources.dto.KeysDTO;
+import com.epam.datalab.backendapi.service.AccessKeyService;
+import com.epam.datalab.exceptions.DatalabException;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.KeyPair;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+@Singleton
+@Slf4j
+public class AccessKeyServiceImpl implements AccessKeyService {
+    @Inject
+    private SelfServiceApplicationConfiguration configuration;
+
+
+    @Override
+    public KeysDTO generateKeys(UserInfo userInfo) {
+        log.debug("Generating new key pair for user {}", userInfo.getName());
+        try (ByteArrayOutputStream publicKeyOut = new ByteArrayOutputStream();
+             ByteArrayOutputStream privateKeyOut = new ByteArrayOutputStream()) {
+            KeyPair pair = KeyPair.genKeyPair(new JSch(), KeyPair.RSA, configuration.getPrivateKeySize());
+            pair.writePublicKey(publicKeyOut, userInfo.getName());
+            pair.writePrivateKey(privateKeyOut);
+            return new KeysDTO(new String(publicKeyOut.toByteArray()),
+                    new String(privateKeyOut.toByteArray()), userInfo.getName());
+        } catch (JSchException | IOException e) {
+            log.error("Can not generate private/public key pair due to: {}", e.getMessage());
+            throw new DatalabException("Can not generate private/public key pair due to: " + e.getMessage(), e);
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/AuditServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/AuditServiceImpl.java
new file mode 100644
index 0000000..161bf2b
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/AuditServiceImpl.java
@@ -0,0 +1,63 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.dao.AuditDAO;
+import com.epam.datalab.backendapi.domain.AuditCreateDTO;
+import com.epam.datalab.backendapi.domain.AuditDTO;
+import com.epam.datalab.backendapi.domain.AuditPaginationDTO;
+import com.epam.datalab.backendapi.service.AuditService;
+import com.google.inject.Inject;
+
+import java.util.List;
+
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.FOLLOW_LINK;
+
+public class AuditServiceImpl implements AuditService {
+    private final AuditDAO auditDAO;
+
+    @Inject
+    public AuditServiceImpl(AuditDAO auditDAO) {
+        this.auditDAO = auditDAO;
+    }
+
+    @Override
+    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(FOLLOW_LINK)
+                .type(audit.getType())
+                .info(audit.getInfo())
+                .build();
+        auditDAO.save(auditDTO);
+    }
+
+    @Override
+    public List<AuditPaginationDTO> getAudit(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes,
+                                             String dateStart, String dateEnd, int pageNumber, int pageSize) {
+        return auditDAO.getAudit(users, projects, resourceNames, resourceTypes, dateStart, dateEnd, pageNumber, pageSize);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BackupServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BackupServiceImpl.java
new file mode 100644
index 0000000..cfd42a0
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BackupServiceImpl.java
@@ -0,0 +1,69 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.BackupDAO;
+import com.epam.datalab.backendapi.resources.dto.BackupInfoRecord;
+import com.epam.datalab.backendapi.service.BackupService;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.backup.EnvBackupDTO;
+import com.epam.datalab.dto.backup.EnvBackupStatus;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.BackupAPI;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+
+import java.util.List;
+
+@Singleton
+public class BackupServiceImpl implements BackupService {
+
+    @Inject
+    @Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
+    private RESTService provisioningService;
+
+    @Inject
+    private BackupDAO backupDao;
+
+    @Override
+    public String createBackup(EnvBackupDTO dto, UserInfo user) {
+        updateStatus(dto, user.getName(), EnvBackupStatus.CREATING);
+        return provisioningService.post(BackupAPI.BACKUP, user.getAccessToken(), dto, String.class);
+    }
+
+    @Override
+    public void updateStatus(EnvBackupDTO dto, String user, EnvBackupStatus status) {
+        backupDao.createOrUpdate(dto, user, status);
+    }
+
+    @Override
+    public List<BackupInfoRecord> getBackups(String userName) {
+        return backupDao.getBackups(userName);
+    }
+
+    @Override
+    public BackupInfoRecord getBackup(String userName, String id) {
+        return backupDao.getBackup(userName, id).orElseThrow(() -> new ResourceNotFoundException(
+                String.format("Backup with id %s was not found for user %s", id, userName)));
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BillingServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BillingServiceImpl.java
new file mode 100644
index 0000000..ef8e379
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BillingServiceImpl.java
@@ -0,0 +1,383 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.BillingDAO;
+import com.epam.datalab.backendapi.dao.ImageExploratoryDAO;
+import com.epam.datalab.backendapi.dao.ProjectDAO;
+import com.epam.datalab.backendapi.domain.BillingReport;
+import com.epam.datalab.backendapi.domain.BillingReportLine;
+import com.epam.datalab.backendapi.domain.BudgetDTO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectEndpointDTO;
+import com.epam.datalab.backendapi.resources.dto.BillingFilter;
+import com.epam.datalab.backendapi.resources.dto.QuotaUsageDTO;
+import com.epam.datalab.backendapi.roles.RoleType;
+import com.epam.datalab.backendapi.roles.UserRoles;
+import com.epam.datalab.backendapi.service.BillingService;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.util.BillingUtils;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.billing.BillingData;
+import com.epam.datalab.dto.billing.BillingResourceType;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.http.client.utils.URIBuilder;
+
+import javax.ws.rs.core.GenericType;
+import java.math.BigDecimal;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Slf4j
+public class BillingServiceImpl implements BillingService {
+    private static final String BILLING_PATH = "/api/billing";
+    private static final String USAGE_DATE_FORMAT = "yyyy-MM";
+
+    private final ProjectService projectService;
+    private final ProjectDAO projectDAO;
+    private final EndpointService endpointService;
+    private final ExploratoryService exploratoryService;
+    private final SelfServiceApplicationConfiguration configuration;
+    private final RESTService provisioningService;
+    private final ImageExploratoryDAO imageExploratoryDao;
+    private final BillingDAO billingDAO;
+
+    @Inject
+    public BillingServiceImpl(ProjectService projectService, ProjectDAO projectDAO, EndpointService endpointService,
+                              ExploratoryService exploratoryService, SelfServiceApplicationConfiguration configuration,
+                              @Named(ServiceConsts.BILLING_SERVICE_NAME) RESTService provisioningService, ImageExploratoryDAO imageExploratoryDao,
+                              BillingDAO billingDAO) {
+        this.projectService = projectService;
+        this.projectDAO = projectDAO;
+        this.endpointService = endpointService;
+        this.exploratoryService = exploratoryService;
+        this.configuration = configuration;
+        this.provisioningService = provisioningService;
+        this.imageExploratoryDao = imageExploratoryDao;
+        this.billingDAO = billingDAO;
+    }
+
+    @Override
+    public BillingReport getBillingReport(UserInfo user, BillingFilter filter) {
+        setUserFilter(user, filter);
+        List<BillingReportLine> billingReportLines = billingDAO.aggregateBillingData(filter)
+                .stream()
+                .peek(this::appendStatuses)
+                .filter(bd -> CollectionUtils.isEmpty(filter.getStatuses()) || filter.getStatuses().contains(bd.getStatus()))
+                .collect(Collectors.toList());
+        final LocalDate min = billingReportLines.stream().min(Comparator.comparing(BillingReportLine::getUsageDateFrom)).map(BillingReportLine::getUsageDateFrom).orElse(null);
+        final LocalDate max = billingReportLines.stream().max(Comparator.comparing(BillingReportLine::getUsageDateTo)).map(BillingReportLine::getUsageDateTo).orElse(null);
+        final double sum = billingReportLines.stream().mapToDouble(BillingReportLine::getCost).sum();
+        final String currency = billingReportLines.stream().map(BillingReportLine::getCurrency).distinct().count() == 1 ? billingReportLines.get(0).getCurrency() : null;
+        return BillingReport.builder()
+                .name("Billing report")
+                .sbn(configuration.getServiceBaseName())
+                .reportLines(billingReportLines)
+                .usageDateFrom(min)
+                .usageDateTo(max)
+                .totalCost(BigDecimal.valueOf(sum).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue())
+                .currency(currency)
+                .isReportHeaderCompletable(hasUserBillingRole(user))
+                .build();
+    }
+
+    @Override
+    public String downloadReport(UserInfo user, BillingFilter filter) {
+        BillingReport report = getBillingReport(user, filter);
+        boolean isReportComplete = report.isReportHeaderCompletable();
+        StringBuilder reportHead = new StringBuilder(BillingUtils.getFirstLine(report.getSbn(), report.getUsageDateFrom(), report.getUsageDateTo()));
+        String stringOfAdjustedHeader = BillingUtils.getHeader(isReportComplete);
+        reportHead.append(stringOfAdjustedHeader);
+        report.getReportLines().forEach(r -> reportHead.append(BillingUtils.printLine(r, isReportComplete)));
+        reportHead.append(BillingUtils.getTotal(report.getTotalCost(), report.getCurrency(), stringOfAdjustedHeader));
+        return reportHead.toString();
+    }
+
+    @Override
+    public BillingReport getExploratoryBillingData(String project, String endpoint, String exploratoryName, List<String> compNames) {
+        List<String> resourceNames = new ArrayList<>(compNames);
+        resourceNames.add(exploratoryName);
+        List<BillingReportLine> billingReportLines = billingDAO.findBillingData(project, endpoint, resourceNames);
+        final double sum = billingReportLines.stream().mapToDouble(BillingReportLine::getCost).sum();
+        List<BillingReportLine> billingData = billingReportLines
+                .stream()
+                .peek(bd -> bd.setCost(BigDecimal.valueOf(bd.getCost()).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()))
+                .collect(Collectors.toList());
+        ;
+        final String currency = billingData.stream().map(BillingReportLine::getCurrency).distinct().count() == 1 ? billingData.get(0).getCurrency() : null;
+        return BillingReport.builder()
+                .name(exploratoryName)
+                .reportLines(billingData)
+                .totalCost(BigDecimal.valueOf(sum).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue())
+                .currency(currency)
+                .build();
+    }
+
+    @Override
+    public void updateRemoteBillingData(UserInfo userInfo) {
+        List<EndpointDTO> endpoints = endpointService.getEndpoints();
+        if (CollectionUtils.isEmpty(endpoints)) {
+            log.error("Cannot update billing info. There are no endpoints");
+            throw new DatalabException("Cannot update billing info. There are no endpoints");
+        }
+
+        Map<EndpointDTO, List<BillingData>> billingDataMap = endpoints
+                .stream()
+                .collect(Collectors.toMap(e -> e, e -> getBillingData(userInfo, e)));
+
+        billingDataMap.forEach((endpointDTO, billingData) -> {
+            log.info("Updating billing information for endpoint {}. Billing data {}", endpointDTO.getName(), billingData);
+            if (!billingData.isEmpty()) {
+                updateBillingData(endpointDTO, billingData, endpoints);
+            }
+        });
+    }
+
+    @Override
+    public QuotaUsageDTO getQuotas(UserInfo userInfo) {
+        int totalQuota = billingDAO.getBillingQuoteUsed();
+        Map<String, Integer> projectQuotas = projectService.getProjects(userInfo)
+                .stream()
+                .collect(Collectors.toMap(ProjectDTO::getName, p -> getBillingProjectQuoteUsed(p.getName())));
+        return QuotaUsageDTO.builder()
+                .totalQuotaUsed(totalQuota)
+                .projectQuotas(projectQuotas)
+                .build();
+    }
+
+    @Override
+    public boolean isProjectQuoteReached(String project) {
+        final Double projectCost = getProjectCost(project);
+        return projectDAO.getAllowedBudget(project)
+                .filter(allowedBudget -> projectCost.intValue() != 0 && allowedBudget <= projectCost)
+                .isPresent();
+    }
+
+    @Override
+    public int getBillingProjectQuoteUsed(String project) {
+        return toPercentage(() -> projectDAO.getAllowedBudget(project), getProjectCost(project));
+    }
+
+    private Double getProjectCost(String project) {
+        final boolean monthlyBudget = Optional.ofNullable(projectService.get(project).getBudget())
+                .map(BudgetDTO::isMonthlyBudget)
+                .orElse(Boolean.FALSE);
+        return monthlyBudget ? billingDAO.getMonthlyProjectCost(project, LocalDate.now()) : billingDAO.getOverallProjectCost(project);
+    }
+
+    private Map<String, BillingReportLine> getBillableResources(List<EndpointDTO> endpoints) {
+        Set<ProjectDTO> projects = new HashSet<>(projectService.getProjects());
+        final Stream<BillingReportLine> ssnBillingDataStream = BillingUtils.ssnBillingDataStream(configuration.getServiceBaseName());
+        final Stream<BillingReportLine> billableEdges = projects
+                .stream()
+                .collect(Collectors.toMap(ProjectDTO::getName, ProjectDTO::getEndpoints))
+                .entrySet()
+                .stream()
+                .flatMap(e -> projectEdges(configuration.getServiceBaseName(), e.getKey(), e.getValue()));
+        final Stream<BillingReportLine> billableSharedEndpoints = endpoints
+                .stream()
+                .flatMap(endpoint -> BillingUtils.sharedEndpointBillingDataStream(endpoint.getName(), configuration.getServiceBaseName()));
+        final Stream<BillingReportLine> billableUserInstances = exploratoryService.findAll(projects)
+                .stream()
+                .filter(userInstance -> Objects.nonNull(userInstance.getExploratoryId()))
+                .flatMap(ui -> BillingUtils.exploratoryBillingDataStream(ui, configuration.getMaxSparkInstanceCount()));
+        final Stream<BillingReportLine> customImages = projects
+                .stream()
+                .map(p -> imageExploratoryDao.getImagesForProject(p.getName()))
+                .flatMap(Collection::stream)
+                .flatMap(i -> BillingUtils.customImageBillingDataStream(i, configuration.getServiceBaseName()));
+
+        final Map<String, BillingReportLine> billableResources = Stream.of(ssnBillingDataStream, billableEdges, billableSharedEndpoints, billableUserInstances, customImages)
+                .flatMap(s -> s)
+                .collect(Collectors.toMap(BillingReportLine::getDatalabId, b -> b));
+        log.debug("Billable resources are: {}", billableResources);
+
+        return billableResources;
+    }
+
+    private Stream<BillingReportLine> projectEdges(String serviceBaseName, String projectName, List<ProjectEndpointDTO> endpoints) {
+        return endpoints
+                .stream()
+                .flatMap(endpoint -> BillingUtils.edgeBillingDataStream(projectName, serviceBaseName, endpoint.getName()));
+    }
+
+    private void updateBillingData(EndpointDTO endpointDTO, List<BillingData> billingData, List<EndpointDTO> endpoints) {
+        final String endpointName = endpointDTO.getName();
+        final CloudProvider cloudProvider = endpointDTO.getCloudProvider();
+        final Map<String, BillingReportLine> billableResources = getBillableResources(endpoints);
+        final Stream<BillingReportLine> billingReportLineStream = billingData
+                .stream()
+                .peek(bd -> bd.setApplication(endpointName))
+                .map(bd -> toBillingReport(bd, getOrDefault(billableResources, bd.getTag())));
+
+        if (cloudProvider == CloudProvider.GCP) {
+            final Map<String, List<BillingReportLine>> gcpBillingData = billingReportLineStream
+                    .collect(Collectors.groupingBy(bd -> bd.getUsageDate().substring(0, USAGE_DATE_FORMAT.length())));
+            updateGcpBillingData(endpointName, gcpBillingData);
+        } else if (cloudProvider == CloudProvider.AWS) {
+            final Map<String, List<BillingReportLine>> awsBillingData = billingReportLineStream
+                    .collect(Collectors.groupingBy(BillingReportLine::getUsageDate));
+            updateAwsBillingData(endpointName, awsBillingData);
+        } else if (cloudProvider == CloudProvider.AZURE) {
+            final List<BillingReportLine> billingReportLines = billingReportLineStream
+                    .collect(Collectors.toList());
+            updateAzureBillingData(billingReportLines);
+        }
+    }
+
+    private BillingReportLine getOrDefault(Map<String, BillingReportLine> billableResources, String tag) {
+        return billableResources.getOrDefault(tag, BillingReportLine.builder().datalabId(tag).build());
+    }
+
+    private void updateGcpBillingData(String endpointName, Map<String, List<BillingReportLine>> billingData) {
+        billingData.forEach((usageDate, billingReportLines) -> {
+            billingDAO.deleteByUsageDateRegex(endpointName, usageDate);
+            billingDAO.save(billingReportLines);
+        });
+    }
+
+    private void updateAwsBillingData(String endpointName, Map<String, List<BillingReportLine>> billingData) {
+        billingData.forEach((usageDate, billingReportLines) -> {
+            billingDAO.deleteByUsageDate(endpointName, usageDate);
+            billingDAO.save(billingReportLines);
+        });
+    }
+
+    private void updateAzureBillingData(List<BillingReportLine> billingReportLines) {
+        billingDAO.save(billingReportLines);
+    }
+
+    private List<BillingData> getBillingData(UserInfo userInfo, EndpointDTO endpointDTO) {
+        try {
+            return provisioningService.get(getBillingUrl(endpointDTO.getUrl(), BILLING_PATH), userInfo.getAccessToken(),
+                    new GenericType<List<BillingData>>() {
+                    });
+        } catch (Exception e) {
+            log.error("Cannot retrieve billing information for {} . Reason {}.", endpointDTO.getName(), e.getMessage(), e);
+            return Collections.emptyList();
+        }
+    }
+
+    private String getBillingUrl(String endpointUrl, String path) {
+        URI uri;
+        try {
+            uri = new URI(endpointUrl);
+        } catch (URISyntaxException e) {
+            log.error("Wrong URI syntax {}", e.getMessage(), e);
+            throw new DatalabException("Wrong URI syntax");
+        }
+        return new URIBuilder()
+                .setScheme(uri.getScheme())
+                .setHost(uri.getHost())
+                .setPort(8088)
+                .setPath(path)
+                .toString();
+    }
+
+    private void appendStatuses(BillingReportLine br) {
+        BillingResourceType resourceType = br.getResourceType();
+        if (BillingResourceType.EDGE == resourceType) {
+            projectService.get(br.getProject()).getEndpoints()
+                    .stream()
+                    .filter(e -> e.getName().equals(br.getResourceName()))
+                    .findAny()
+                    .ifPresent(e -> br.setStatus(e.getStatus()));
+        } else if (BillingResourceType.EXPLORATORY == resourceType) {
+            exploratoryService.getUserInstance(br.getUser(), br.getProject(), br.getResourceName())
+                    .ifPresent(ui -> br.setStatus(UserInstanceStatus.of(ui.getStatus())));
+        } else if (BillingResourceType.COMPUTATIONAL == resourceType) {
+            exploratoryService.getUserInstance(br.getUser(), br.getProject(), br.getExploratoryName(), true)
+                    .flatMap(ui -> ui.getResources()
+                            .stream()
+                            .filter(cr -> cr.getComputationalName().equals(br.getResourceName()))
+                            .findAny())
+                    .ifPresent(cr -> br.setStatus(UserInstanceStatus.of(cr.getStatus())));
+        }
+    }
+
+    /**
+     * @param userInfo user's properties for current session
+     * @return true, if user has be billing role
+     */
+    private boolean hasUserBillingRole(UserInfo userInfo) {
+        return UserRoles.checkAccess(userInfo, RoleType.PAGE, "/api/infrastructure_provision/billing", userInfo.getRoles());
+    }
+
+    private void setUserFilter(UserInfo userInfo, BillingFilter filter) {
+        if (!hasUserBillingRole(userInfo)) {
+            filter.setUsers(Lists.newArrayList(userInfo.getName()));
+        }
+    }
+
+    private BillingReportLine toBillingReport(BillingData billingData, BillingReportLine billingReportLine) {
+        return BillingReportLine.builder()
+                .application(billingData.getApplication())
+                .cost(billingData.getCost())
+                .currency(billingData.getCurrency())
+                .product(billingData.getProduct())
+                .project(billingReportLine.getProject())
+                .endpoint(billingReportLine.getEndpoint())
+                .usageDateFrom(billingData.getUsageDateFrom())
+                .usageDateTo(billingData.getUsageDateTo())
+                .usageDate(billingData.getUsageDate())
+                .usageType(billingData.getUsageType())
+                .user(billingReportLine.getUser())
+                .datalabId(billingData.getTag())
+                .resourceType(billingReportLine.getResourceType())
+                .resourceName(billingReportLine.getResourceName())
+                .shape(billingReportLine.getShape())
+                .exploratoryName(billingReportLine.getExploratoryName())
+                .build();
+    }
+
+    private Integer toPercentage(Supplier<Optional<Integer>> allowedBudget, Double totalCost) {
+        return allowedBudget.get()
+                .map(userBudget -> (totalCost * 100) / userBudget)
+                .map(Double::intValue)
+                .orElse(BigDecimal.ZERO.intValue());
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BucketServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BucketServiceImpl.java
new file mode 100644
index 0000000..7729dea
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BucketServiceImpl.java
@@ -0,0 +1,175 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Audit;
+import com.epam.datalab.backendapi.annotation.Info;
+import com.epam.datalab.backendapi.annotation.ResourceName;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.service.BucketService;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.bucket.BucketDTO;
+import com.epam.datalab.dto.bucket.BucketDeleteDTO;
+import com.epam.datalab.dto.bucket.FolderUploadDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpStatus;
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
+import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.DELETE;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.DOWNLOAD;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.UPLOAD;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.BUCKET;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
+
+@Slf4j
+public class BucketServiceImpl implements BucketService {
+    private static final String BUCKET_GET_OBJECTS = "%sbucket/%s";
+    private static final String BUCKET_UPLOAD_OBJECT = "%sbucket/upload";
+    private static final String BUCKET_UPLOAD_FOLDER = "%sbucket/folder/upload";
+    private static final String BUCKET_DOWNLOAD_OBJECT = "%sbucket/%s/object/%s/download";
+    private static final String BUCKET_DELETE_OBJECT = "%sbucket/objects/delete";
+    private static final String SOMETHING_WENT_WRONG_MESSAGE = "Something went wrong. Response status is %s ";
+
+    private final EndpointService endpointService;
+    private final RESTService provisioningService;
+
+    @Inject
+    public BucketServiceImpl(EndpointService endpointService, @Named(ServiceConsts.BUCKET_SERVICE_NAME) RESTService provisioningService) {
+        this.endpointService = endpointService;
+        this.provisioningService = provisioningService;
+    }
+
+    @Override
+    public List<BucketDTO> getObjects(UserInfo userInfo, String bucket, String endpoint) {
+        try {
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            return provisioningService.get(String.format(BUCKET_GET_OBJECTS, endpointDTO.getUrl(), bucket), userInfo.getAccessToken(), new GenericType<List<BucketDTO>>() {
+            });
+        } catch (Exception e) {
+            log.error("Cannot get objects from bucket {} for user {}, endpoint {}. Reason {}", bucket, userInfo.getName(), endpoint, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot get objects from bucket %s for user %s, endpoint %s. Reason %s", bucket, userInfo.getName(), endpoint, e.getMessage()));
+        }
+    }
+
+    @Audit(action = UPLOAD, type = BUCKET)
+    @Override
+    public void uploadObject(@User UserInfo userInfo, @ResourceName String bucket, String object, String endpoint, InputStream inputStream, String contentType, long fileSize, @Info String auditInfo) {
+        log.info("Uploading file {} for user {} to bucket {}", object, userInfo.getName(), bucket);
+        try {
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            FormDataMultiPart formData = getFormDataMultiPart(bucket, object, inputStream, contentType, fileSize);
+            Response response = provisioningService.postForm(String.format(BUCKET_UPLOAD_OBJECT, endpointDTO.getUrl()), userInfo.getAccessToken(), formData, Response.class);
+            if (response.getStatus() != HttpStatus.SC_OK) {
+                throw new DatalabException(String.format(SOMETHING_WENT_WRONG_MESSAGE, response.getStatus()));
+            }
+        } catch (Exception e) {
+            log.error("Cannot upload object {} to bucket {} for user {}, endpoint {}. Reason {}", object, bucket, userInfo.getName(), endpoint, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot upload object %s to bucket %s for user %s, endpoint %s. Reason %s", object, bucket, userInfo.getName(), endpoint, e.getMessage()));
+        }
+        log.info("Finished uploading file {} for user {} to bucket {}", object, userInfo.getName(), bucket);
+    }
+
+    @Audit(action = UPLOAD, type = BUCKET)
+    @Override
+    public void uploadFolder(@User UserInfo userInfo, @ResourceName String bucket, String folder, String endpoint, @Info String auditInfo) {
+        log.info("Uploading folder {} for user {} to bucket {}", folder, userInfo.getName(), bucket);
+        try {
+            if (!folder.endsWith("/")) {
+                throw new DatalabException("Folder doesn't end with '/'");
+            }
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            FolderUploadDTO dto = new FolderUploadDTO(bucket, folder);
+            Response response = provisioningService.post(String.format(BUCKET_UPLOAD_FOLDER, endpointDTO.getUrl()), userInfo.getAccessToken(), dto, Response.class);
+            if (response.getStatus() != HttpStatus.SC_OK) {
+                throw new DatalabException(String.format(SOMETHING_WENT_WRONG_MESSAGE, response.getStatus()));
+            }
+        } catch (Exception e) {
+            log.error("Cannot upload folder {} to bucket {} for user {}, endpoint {}. Reason {}", folder, bucket, userInfo.getName(), endpoint, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot upload object %s to bucket %s for user %s, endpoint %s. Reason %s", folder, bucket, userInfo.getName(), endpoint, e.getMessage()));
+        }
+        log.info("Finished uploading folder {} for user {} to bucket {}", folder, userInfo.getName(), bucket);
+    }
+
+    @Audit(action = DOWNLOAD, type = BUCKET)
+    @Override
+    public void downloadObject(@User UserInfo userInfo, @ResourceName String bucket, String object, String endpoint, HttpServletResponse resp, @Info String auditInfo) {
+        log.info("Downloading file {} for user {} from bucket {}", object, userInfo.getName(), bucket);
+        EndpointDTO endpointDTO = endpointService.get(endpoint);
+        try (InputStream inputStream = provisioningService.getWithMediaTypes(String.format(BUCKET_DOWNLOAD_OBJECT, endpointDTO.getUrl(), bucket, encodeObject(object)), userInfo.getAccessToken(),
+                InputStream.class, APPLICATION_JSON, APPLICATION_OCTET_STREAM); ServletOutputStream outputStream = resp.getOutputStream()) {
+            IOUtils.copyLarge(inputStream, outputStream);
+            log.info("Finished downloading file {} for user {} from bucket {}", object, userInfo.getName(), bucket);
+        } catch (Exception e) {
+            log.error("Cannot upload object {} from bucket {} for user {}, endpoint {}. Reason {}", object, bucket, userInfo.getName(), endpoint, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot download object %s from bucket %s for user %s, endpoint %s. Reason %s", object, bucket, userInfo.getName(), endpoint, e.getMessage()));
+        }
+    }
+
+    @Audit(action = DELETE, type = BUCKET)
+    @Override
+    public void deleteObjects(@User UserInfo userInfo, @ResourceName String bucket, List<String> objects, String endpoint, @Info String auditInfo) {
+        try {
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            BucketDeleteDTO bucketDeleteDTO = new BucketDeleteDTO(bucket, objects);
+            Response response = provisioningService.post(String.format(BUCKET_DELETE_OBJECT, endpointDTO.getUrl()), userInfo.getAccessToken(), bucketDeleteDTO, Response.class);
+            if (response.getStatus() != HttpStatus.SC_OK) {
+                throw new DatalabException(String.format(SOMETHING_WENT_WRONG_MESSAGE, response.getStatus()));
+            }
+        } catch (Exception e) {
+            log.error("Cannot delete objects {} from bucket {} for user {}, endpoint {}. Reason {}", objects, bucket, userInfo.getName(), endpoint, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot delete objects %s from bucket %s for user %s, endpoint %s. Reason %s", objects, bucket, userInfo.getName(), endpoint, e.getMessage()));
+        }
+    }
+
+    private String encodeObject(String object) throws UnsupportedEncodingException {
+        return URLEncoder.encode(object, StandardCharsets.UTF_8.toString()).replace("+", "%20");
+    }
+
+    private FormDataMultiPart getFormDataMultiPart(String bucket, String object, InputStream inputStream, String contentType, long fileSize) {
+        StreamDataBodyPart filePart = new StreamDataBodyPart("file", inputStream, object, MediaType.valueOf(contentType));
+        FormDataMultiPart formData = new FormDataMultiPart();
+        formData.field("bucket", bucket);
+        formData.field("object", object);
+        formData.field("file-size", String.valueOf(fileSize));
+        formData.bodyPart(filePart);
+        return formData;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ComputationalServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ComputationalServiceImpl.java
new file mode 100644
index 0000000..9e0e129
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ComputationalServiceImpl.java
@@ -0,0 +1,396 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Audit;
+import com.epam.datalab.backendapi.annotation.BudgetLimited;
+import com.epam.datalab.backendapi.annotation.Info;
+import com.epam.datalab.backendapi.annotation.Project;
+import com.epam.datalab.backendapi.annotation.ResourceName;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.dao.ComputationalDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.resources.dto.ComputationalCreateFormDTO;
+import com.epam.datalab.backendapi.resources.dto.ComputationalTemplatesDTO;
+import com.epam.datalab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
+import com.epam.datalab.backendapi.service.ComputationalService;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.InfrastructureTemplateService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.service.TagService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.epam.datalab.dto.base.computational.FullComputationalTemplate;
+import com.epam.datalab.dto.computational.ComputationalClusterConfigDTO;
+import com.epam.datalab.dto.computational.ComputationalStatusDTO;
+import com.epam.datalab.dto.computational.ComputationalTerminateDTO;
+import com.epam.datalab.dto.computational.SparkStandaloneClusterResource;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.ComputationalAPI;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.CREATE;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.RECONFIGURE;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.START;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.STOP;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.TERMINATE;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.COMPUTE;
+import static com.epam.datalab.dto.UserInstanceStatus.CREATING;
+import static com.epam.datalab.dto.UserInstanceStatus.FAILED;
+import static com.epam.datalab.dto.UserInstanceStatus.RECONFIGURING;
+import static com.epam.datalab.dto.UserInstanceStatus.STARTING;
+import static com.epam.datalab.dto.UserInstanceStatus.STOPPING;
+import static com.epam.datalab.dto.UserInstanceStatus.TERMINATING;
+import static com.epam.datalab.dto.base.DataEngineType.CLOUD_SERVICE;
+import static com.epam.datalab.dto.base.DataEngineType.SPARK_STANDALONE;
+import static com.epam.datalab.rest.contracts.ComputationalAPI.COMPUTATIONAL_CREATE_CLOUD_SPECIFIC;
+
+@Singleton
+@Slf4j
+public class ComputationalServiceImpl implements ComputationalService {
+
+    private static final String COULD_NOT_UPDATE_THE_STATUS_MSG_FORMAT = "Could not update the status of " +
+            "computational resource {} for user {}";
+    private static final EnumMap<DataEngineType, String> DATA_ENGINE_TYPE_TERMINATE_URLS;
+    private static final String DATAENGINE_NOT_PRESENT_FORMAT = "There is no %s dataengine %s for exploratory %s";
+    private static final String RUNNING_COMP_RES_NOT_FOUND = "Running computational resource with " +
+            "name %s for exploratory %s not found";
+
+    static {
+        DATA_ENGINE_TYPE_TERMINATE_URLS = new EnumMap<>(DataEngineType.class);
+        DATA_ENGINE_TYPE_TERMINATE_URLS.put(SPARK_STANDALONE, ComputationalAPI.COMPUTATIONAL_TERMINATE_SPARK);
+        DATA_ENGINE_TYPE_TERMINATE_URLS.put(CLOUD_SERVICE, ComputationalAPI.COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC);
+    }
+
+    private final ProjectService projectService;
+    private final ExploratoryDAO exploratoryDAO;
+    private final ComputationalDAO computationalDAO;
+    private final RESTService provisioningService;
+    private final RequestBuilder requestBuilder;
+    private final RequestId requestId;
+    private final TagService tagService;
+    private final EndpointService endpointService;
+    private final InfrastructureTemplateService templateService;
+
+    @Inject
+    public ComputationalServiceImpl(ProjectService projectService, ExploratoryDAO exploratoryDAO, ComputationalDAO computationalDAO,
+                                    @Named(ServiceConsts.PROVISIONING_SERVICE_NAME) RESTService provisioningService,
+                                    RequestBuilder requestBuilder, RequestId requestId, TagService tagService,
+                                    EndpointService endpointService, InfrastructureTemplateService templateService) {
+        this.projectService = projectService;
+        this.exploratoryDAO = exploratoryDAO;
+        this.computationalDAO = computationalDAO;
+        this.provisioningService = provisioningService;
+        this.requestBuilder = requestBuilder;
+        this.requestId = requestId;
+        this.tagService = tagService;
+        this.endpointService = endpointService;
+        this.templateService = templateService;
+    }
+
+
+    @Override
+    public ComputationalTemplatesDTO getComputationalNamesAndTemplates(UserInfo user, String project, String endpoint) {
+        List<FullComputationalTemplate> computationalTemplates = templateService.getComputationalTemplates(user, project, endpoint);
+        List<UserInstanceDTO> userInstances = exploratoryDAO.fetchExploratoryFieldsForProjectWithComp(project);
+
+        List<String> projectComputations = userInstances
+                .stream()
+                .map(UserInstanceDTO::getResources)
+                .flatMap(Collection::stream)
+                .map(UserComputationalResource::getComputationalName)
+                .collect(Collectors.toList());
+        List<String> userComputations = userInstances
+                .stream()
+                .filter(instance -> instance.getUser().equalsIgnoreCase(user.getName()))
+                .map(UserInstanceDTO::getResources)
+                .flatMap(Collection::stream)
+                .map(UserComputationalResource::getComputationalName)
+                .collect(Collectors.toList());
+
+        return new ComputationalTemplatesDTO(computationalTemplates, userComputations, projectComputations);
+    }
+
+    @BudgetLimited
+    @Audit(action = CREATE, type = COMPUTE)
+    @Override
+    public boolean createSparkCluster(@User UserInfo userInfo, @ResourceName String resourceName, SparkStandaloneClusterCreateForm form, @Project String project,
+                                      @Info String auditInfo) {
+        final ProjectDTO projectDTO = projectService.get(project);
+        final UserInstanceDTO instance =
+                exploratoryDAO.fetchExploratoryFields(userInfo.getName(), project, form.getNotebookName());
+        final SparkStandaloneClusterResource compResource = createInitialComputationalResource(form);
+        compResource.setTags(tagService.getResourceTags(userInfo, instance.getEndpoint(), project,
+                form.getCustomTag()));
+        if (computationalDAO.addComputational(userInfo.getName(), form.getNotebookName(), project, compResource)) {
+            try {
+                EndpointDTO endpointDTO = endpointService.get(instance.getEndpoint());
+                ComputationalBase<?> dto = requestBuilder.newComputationalCreate(userInfo, projectDTO, instance, form, endpointDTO);
+
+                String uuid =
+                        provisioningService.post(endpointDTO.getUrl() + ComputationalAPI.COMPUTATIONAL_CREATE_SPARK,
+                                userInfo.getAccessToken(), dto, String.class);
+                requestId.put(userInfo.getName(), uuid);
+                return true;
+            } catch (RuntimeException e) {
+                try {
+                    updateComputationalStatus(userInfo.getName(), project, form.getNotebookName(), form.getName(), FAILED);
+                } catch (DatalabException d) {
+                    log.error(COULD_NOT_UPDATE_THE_STATUS_MSG_FORMAT, form.getName(), userInfo.getName(), d);
+                }
+                throw e;
+            }
+        } else {
+            log.debug("Computational with name {} is already existing for user {}", form.getName(),
+                    userInfo.getName());
+            return false;
+        }
+    }
+
+    @Audit(action = TERMINATE, type = COMPUTE)
+    @Override
+    public void terminateComputational(@User UserInfo userInfo, String resourceCreator, @Project String project, String exploratoryName, @ResourceName String computationalName,
+                                       @Info String auditInfo) {
+        try {
+            updateComputationalStatus(resourceCreator, project, exploratoryName, computationalName, TERMINATING);
+
+            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(resourceCreator, userInstanceDTO, compResource, endpointDTO);
+
+            final String provisioningUrl = Optional.ofNullable(DATA_ENGINE_TYPE_TERMINATE_URLS.get(dataEngineType))
+                    .orElseThrow(UnsupportedOperationException::new);
+            final String uuid = provisioningService.post(endpointDTO.getUrl() + provisioningUrl, userInfo.getAccessToken(), dto, String.class);
+            requestId.put(resourceCreator, uuid);
+        } catch (RuntimeException re) {
+            try {
+                updateComputationalStatus(resourceCreator, project, exploratoryName, computationalName, FAILED);
+            } catch (DatalabException e) {
+                log.error(COULD_NOT_UPDATE_THE_STATUS_MSG_FORMAT, computationalName, resourceCreator, e);
+            }
+            throw re;
+        }
+    }
+
+    @BudgetLimited
+    @Audit(action = CREATE, type = COMPUTE)
+    @Override
+    public boolean createDataEngineService(@User UserInfo userInfo, @ResourceName String resourceName, ComputationalCreateFormDTO formDTO,
+                                           UserComputationalResource computationalResource, @Project String project, @Info String auditInfo) {
+        final ProjectDTO projectDTO = projectService.get(project);
+        final UserInstanceDTO instance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), project, formDTO
+                .getNotebookName());
+        final Map<String, String> tags = tagService.getResourceTags(userInfo, instance.getEndpoint(), project,
+                formDTO.getCustomTag());
+        computationalResource.setTags(tags);
+        boolean isAdded = computationalDAO.addComputational(userInfo.getName(), formDTO.getNotebookName(), project,
+                computationalResource);
+
+        if (isAdded) {
+            try {
+                EndpointDTO endpointDTO = endpointService.get(instance.getEndpoint());
+                String uuid =
+                        provisioningService.post(endpointDTO.getUrl() + COMPUTATIONAL_CREATE_CLOUD_SPECIFIC,
+                                userInfo.getAccessToken(),
+                                requestBuilder.newComputationalCreate(userInfo, projectDTO, instance, formDTO, endpointDTO),
+                                String.class);
+                requestId.put(userInfo.getName(), uuid);
+                return true;
+            } catch (Exception t) {
+                try {
+                    updateComputationalStatus(userInfo.getName(), project, formDTO.getNotebookName(),
+                            formDTO.getName(), FAILED);
+                } catch (DatalabException e) {
+                    log.error(COULD_NOT_UPDATE_THE_STATUS_MSG_FORMAT, formDTO.getName(), userInfo.getName(), e);
+                }
+                throw new DatalabException("Could not send request for creation the computational resource " + formDTO
+                        .getName() + ": " + t.getLocalizedMessage(), t);
+            }
+        } else {
+            log.debug("Used existing computational resource {} for user {}", formDTO.getName(), userInfo.getName());
+            return false;
+        }
+    }
+
+    @Audit(action = STOP, type = COMPUTE)
+    @Override
+    public void stopSparkCluster(@User UserInfo userInfo, String resourceCreator, @Project String project, String expName, @ResourceName String compName, @Info String auditInfo) {
+        final UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(resourceCreator, project, expName, true);
+        final UserInstanceStatus requiredStatus = UserInstanceStatus.RUNNING;
+        if (computationalWithStatusResourceExist(compName, userInstance, requiredStatus)) {
+            log.debug("{} spark cluster {} for userInstance {}", STOPPING.toString(), compName, expName);
+            updateComputationalStatus(resourceCreator, project, expName, compName, STOPPING);
+            EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
+            final String uuid = provisioningService.post(endpointDTO.getUrl() + ComputationalAPI.COMPUTATIONAL_STOP_SPARK,
+                    userInfo.getAccessToken(),
+                    requestBuilder.newComputationalStop(resourceCreator, userInstance, compName, endpointDTO),
+                    String.class);
+            requestId.put(resourceCreator, uuid);
+        } else {
+            throw new IllegalStateException(String.format(DATAENGINE_NOT_PRESENT_FORMAT, requiredStatus.toString(), compName, expName));
+        }
+
+    }
+
+    @BudgetLimited
+    @Audit(action = START, type = COMPUTE)
+    @Override
+    public void startSparkCluster(@User UserInfo userInfo, String expName, @ResourceName String compName, @Project String project, @Info String auditInfo) {
+        final UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), project, expName, true);
+        final UserInstanceStatus requiredStatus = UserInstanceStatus.STOPPED;
+        if (computationalWithStatusResourceExist(compName, userInstance, requiredStatus)) {
+            log.debug("{} spark cluster {} for userInstance {}", STARTING.toString(), compName, expName);
+            updateComputationalStatus(userInfo.getName(), project, expName, compName, STARTING);
+            EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
+            final String uuid = provisioningService.post(endpointDTO.getUrl() + ComputationalAPI.COMPUTATIONAL_START_SPARK,
+                    userInfo.getAccessToken(),
+                    requestBuilder.newComputationalStart(userInfo, userInstance, compName, endpointDTO),
+                    String.class);
+            requestId.put(userInfo.getName(), uuid);
+        } else {
+            throw new IllegalStateException(String.format(DATAENGINE_NOT_PRESENT_FORMAT, requiredStatus.toString(), compName, expName));
+        }
+    }
+
+    @Audit(action = RECONFIGURE, type = COMPUTE)
+    @Override
+    public void updateSparkClusterConfig(@User UserInfo userInfo, @Project String project, String exploratoryName, @ResourceName String computationalName, List<ClusterConfig> config, @Info String auditInfo) {
+        final String userName = userInfo.getName();
+        final String token = userInfo.getAccessToken();
+        final UserInstanceDTO userInstanceDTO = exploratoryDAO
+                .fetchExploratoryFields(userName, project, exploratoryName, true);
+        final UserComputationalResource compResource = userInstanceDTO
+                .getResources()
+                .stream()
+                .filter(cr -> cr.getComputationalName().equals(computationalName) && cr.getStatus().equals(UserInstanceStatus.RUNNING.toString()))
+                .findAny()
+                .orElseThrow(() -> new ResourceNotFoundException(String.format(RUNNING_COMP_RES_NOT_FOUND,
+                        computationalName, exploratoryName)));
+        EndpointDTO endpointDTO = endpointService.get(userInstanceDTO.getEndpoint());
+        final ComputationalClusterConfigDTO clusterConfigDto = requestBuilder.newClusterConfigUpdate(userInfo,
+                userInstanceDTO, compResource, config, endpointDTO);
+        final String uuid =
+                provisioningService.post(endpointDTO.getUrl() + ComputationalAPI.COMPUTATIONAL_RECONFIGURE_SPARK,
+                        token, clusterConfigDto, String.class);
+        computationalDAO.updateComputationalFields(new ComputationalStatusDTO()
+                .withProject(userInstanceDTO.getProject())
+                .withComputationalName(computationalName)
+                .withExploratoryName(exploratoryName)
+                .withConfig(config)
+                .withStatus(RECONFIGURING.toString())
+                .withUser(userName));
+        requestId.put(userName, uuid);
+
+    }
+
+    /**
+     * Returns computational resource's data by name for user's exploratory.
+     *
+     * @param user              user
+     * @param project           name of project
+     * @param exploratoryName   name of exploratory.
+     * @param computationalName name of computational resource.
+     * @return corresponding computational resource's data or empty data if resource doesn't exist.
+     */
+    @Override
+    public Optional<UserComputationalResource> getComputationalResource(String user, String project, String exploratoryName, String computationalName) {
+        try {
+            return Optional.of(computationalDAO.fetchComputationalFields(user, project, exploratoryName, computationalName));
+        } catch (DatalabException e) {
+            log.warn("Computational resource {} affiliated with exploratory {} for user {} not found.", computationalName, exploratoryName, user, e);
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public List<ClusterConfig> getClusterConfig(UserInfo userInfo, String project, String exploratoryName, String computationalName) {
+        return computationalDAO.getClusterConfig(userInfo.getName(), project, exploratoryName, computationalName);
+    }
+
+    /**
+     * Updates the status of computational resource in database.
+     *
+     * @param user              user name.
+     * @param project           project name
+     * @param exploratoryName   name of exploratory.
+     * @param computationalName name of computational resource.
+     * @param status            status
+     */
+    private void updateComputationalStatus(String user, String project, String exploratoryName, String computationalName, UserInstanceStatus status) {
+        ComputationalStatusDTO computationalStatus = new ComputationalStatusDTO()
+                .withUser(user)
+                .withProject(project)
+                .withExploratoryName(exploratoryName)
+                .withComputationalName(computationalName)
+                .withStatus(status);
+
+        computationalDAO.updateComputationalStatus(computationalStatus);
+    }
+
+    private SparkStandaloneClusterResource createInitialComputationalResource(SparkStandaloneClusterCreateForm form) {
+        return SparkStandaloneClusterResource.builder()
+                .computationalName(form.getName())
+                .imageName(form.getImage())
+                .templateName(form.getTemplateName())
+                .status(CREATING.toString())
+                .dataEngineInstanceCount(form.getDataEngineInstanceCount())
+                .dataEngineInstanceShape(form.getDataEngineInstanceShape())
+                .config(form.getConfig())
+                .build();
+    }
+
+    private boolean computationalWithStatusResourceExist(String compName, UserInstanceDTO ui, UserInstanceStatus status) {
+        return ui.getResources()
+                .stream()
+                .anyMatch(c -> computationalWithNameAndStatus(compName, c, status));
+    }
+
+    private boolean computationalWithNameAndStatus(String computationalName, UserComputationalResource compResource, UserInstanceStatus status) {
+        return compResource.getStatus().equals(status.toString()) &&
+                compResource.getDataEngineType() == SPARK_STANDALONE &&
+                compResource.getComputationalName().equals(computationalName);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EndpointServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EndpointServiceImpl.java
new file mode 100644
index 0000000..cede329
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EndpointServiceImpl.java
@@ -0,0 +1,193 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Audit;
+import com.epam.datalab.backendapi.annotation.ResourceName;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.dao.EndpointDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.UserRoleDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.EndpointResourcesDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceConflictException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.core.Response;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.CONNECT;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.DISCONNECT;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.ENDPOINT;
+
+
+@Slf4j
+public class EndpointServiceImpl implements EndpointService {
+    private static final String HEALTH_CHECK = "healthcheck";
+    private final EndpointDAO endpointDAO;
+    private final ProjectService projectService;
+    private final ExploratoryDAO exploratoryDAO;
+    private final RESTService provisioningService;
+    private final UserRoleDAO userRoleDao;
+
+    @Inject
+    public EndpointServiceImpl(EndpointDAO endpointDAO, ProjectService projectService, ExploratoryDAO exploratoryDAO,
+                               @Named(ServiceConsts.PROVISIONING_SERVICE_NAME) RESTService provisioningService,
+                               UserRoleDAO userRoleDao) {
+
+        this.endpointDAO = endpointDAO;
+        this.projectService = projectService;
+        this.exploratoryDAO = exploratoryDAO;
+        this.provisioningService = provisioningService;
+        this.userRoleDao = userRoleDao;
+    }
+
+    @Override
+    public List<EndpointDTO> getEndpoints() {
+        return endpointDAO.getEndpoints();
+    }
+
+    @Override
+    public List<EndpointDTO> getEndpointsWithStatus(EndpointDTO.EndpointStatus status) {
+        return endpointDAO.getEndpointsWithStatus(status.name());
+    }
+
+    @Override
+    public EndpointResourcesDTO getEndpointResources(String endpoint) {
+        List<UserInstanceDTO> exploratories = exploratoryDAO.fetchExploratoriesByEndpointWhereStatusNotIn(endpoint,
+                Arrays.asList(UserInstanceStatus.TERMINATED, UserInstanceStatus.FAILED));
+
+        List<ProjectDTO> projects = projectService.getProjectsByEndpoint(endpoint);
+
+        return new EndpointResourcesDTO(exploratories, projects);
+    }
+
+    @Override
+    public EndpointDTO get(String name) {
+        return endpointDAO.get(name)
+                .orElseThrow(() -> new ResourceNotFoundException("Endpoint with name " + name + " not found"));
+    }
+
+    /**
+     * Create new endpoint object in the System.
+     * The Endpoint objects should contain Unique values of the 'url' and 'name' fields,
+     * i.e two objects with same URLs should not be created in the system.
+     *
+     * @param userInfo     user properties
+     * @param resourceName name of the endpoint
+     * @param endpointDTO  object with endpoint fields
+     */
+    @Audit(action = CONNECT, type = ENDPOINT)
+    @Override
+    public void create(@User UserInfo userInfo, @ResourceName String resourceName, EndpointDTO endpointDTO) {
+        if (endpointDAO.get(endpointDTO.getName()).isPresent()) {
+            throw new ResourceConflictException("The Endpoint with this name exists in system");
+        }
+        if (endpointDAO.getEndpointWithUrl(endpointDTO.getUrl()).isPresent()) {
+            throw new ResourceConflictException("The Endpoint URL with this address exists in system");
+        }
+        CloudProvider cloudProvider = checkUrl(userInfo, endpointDTO.getUrl());
+        if (Objects.isNull(cloudProvider)) {
+            throw new DatalabException("CloudProvider cannot be null");
+        }
+        endpointDAO.create(new EndpointDTO(endpointDTO.getName(), endpointDTO.getUrl(), endpointDTO.getAccount(),
+                endpointDTO.getTag(), EndpointDTO.EndpointStatus.ACTIVE, cloudProvider));
+        userRoleDao.updateMissingRoles(cloudProvider);
+    }
+
+    @Override
+    public void updateEndpointStatus(String name, EndpointDTO.EndpointStatus status) {
+        endpointDAO.updateEndpointStatus(name, status.name());
+    }
+
+    @Override
+    public void remove(UserInfo userInfo, String name) {
+        EndpointDTO endpointDTO = endpointDAO.get(name).orElseThrow(() -> new ResourceNotFoundException(String.format("Endpoint %s does not exist", name)));
+        List<ProjectDTO> projects = projectService.getProjectsByEndpoint(name);
+        checkProjectEndpointResourcesStatuses(projects, name);
+        CloudProvider cloudProvider = endpointDTO.getCloudProvider();
+        removeEndpoint(userInfo, name, cloudProvider, projects);
+    }
+
+    @Audit(action = DISCONNECT, type = ENDPOINT)
+    public void removeEndpoint(@User UserInfo userInfo, @ResourceName String name, CloudProvider cloudProvider, List<ProjectDTO> projects) {
+        removeEndpointInAllProjects(userInfo, name, projects);
+        endpointDAO.remove(name);
+        List<CloudProvider> remainingProviders = endpointDAO.getEndpoints()
+                .stream()
+                .map(EndpointDTO::getCloudProvider)
+                .collect(Collectors.toList());
+        userRoleDao.removeUnnecessaryRoles(cloudProvider, remainingProviders);
+    }
+
+    @Override
+    public void removeEndpointInAllProjects(UserInfo userInfo, String endpointName, List<ProjectDTO> projects) {
+        projects.forEach(project -> projectService.terminateEndpoint(userInfo, endpointName, project.getName()));
+    }
+
+    @Override
+    public CloudProvider checkUrl(UserInfo userInfo, String url) {
+        Response response;
+        CloudProvider cloudProvider;
+        try {
+            response = provisioningService.get(url + HEALTH_CHECK, userInfo.getAccessToken(), Response.class);
+            cloudProvider = response.readEntity(CloudProvider.class);
+        } catch (Exception e) {
+            log.error("Cannot connect to url '{}'. {}", url, e.getMessage(), e);
+            throw new DatalabException(String.format("Cannot connect to url '%s'.", url));
+        }
+        if (response.getStatus() != 200) {
+            log.warn("Endpoint url {} is not valid", url);
+            throw new ResourceNotFoundException(String.format("Endpoint url '%s' is not valid", url));
+        }
+        return cloudProvider;
+    }
+
+    private void checkProjectEndpointResourcesStatuses(List<ProjectDTO> projects, String endpoint) {
+        boolean isTerminationEnabled = projects.stream()
+                .anyMatch(p -> !projectService.checkExploratoriesAndComputationalProgress(p.getName(), Collections.singletonList(endpoint)) ||
+                        p.getEndpoints().stream()
+                                .anyMatch(e -> e.getName().equals(endpoint) &&
+                                        Arrays.asList(UserInstanceStatus.CREATING, UserInstanceStatus.STARTING, UserInstanceStatus.STOPPING,
+                                                UserInstanceStatus.TERMINATING).contains(e.getStatus())));
+
+        if (isTerminationEnabled) {
+            throw new ResourceConflictException(("Can not terminate resources of endpoint because one of project " +
+                    "resource is in processing stage"));
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImpl.java
new file mode 100644
index 0000000..7f0866e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImpl.java
@@ -0,0 +1,233 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Project;
+import com.epam.datalab.backendapi.annotation.ProjectAdmin;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.dao.EnvDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.UserSettingsDAO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.resources.dto.UserDTO;
+import com.epam.datalab.backendapi.resources.dto.UserResourceInfo;
+import com.epam.datalab.backendapi.service.ComputationalService;
+import com.epam.datalab.backendapi.service.EnvironmentService;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.exceptions.ResourceConflictException;
+import com.epam.datalab.model.ResourceEnum;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import static com.epam.datalab.backendapi.resources.dto.UserDTO.Status.ACTIVE;
+import static com.epam.datalab.backendapi.resources.dto.UserDTO.Status.NOT_ACTIVE;
+import static com.epam.datalab.dto.UserInstanceStatus.CREATING;
+import static com.epam.datalab.dto.UserInstanceStatus.CREATING_IMAGE;
+import static com.epam.datalab.dto.UserInstanceStatus.RUNNING;
+import static com.epam.datalab.dto.UserInstanceStatus.STARTING;
+import static com.epam.datalab.rest.contracts.ComputationalAPI.AUDIT_MESSAGE;
+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 AUDIT_QUOTA_MESSAGE = "Billing quota reached";
+	private static final String DATALAB_SYSTEM_USER = "DataLab system user";
+
+	private final EnvDAO envDAO;
+	private final UserSettingsDAO settingsDAO;
+	private final ExploratoryDAO exploratoryDAO;
+	private final ExploratoryService exploratoryService;
+	private final ComputationalService computationalService;
+	private final SecurityService securityService;
+	private final ProjectService projectService;
+
+	@Inject
+	public EnvironmentServiceImpl(EnvDAO envDAO, UserSettingsDAO settingsDAO, ExploratoryDAO exploratoryDAO,
+								  ExploratoryService exploratoryService, ComputationalService computationalService,
+								  SecurityService securityService, ProjectService projectService) {
+		this.envDAO = envDAO;
+		this.settingsDAO = settingsDAO;
+		this.exploratoryDAO = exploratoryDAO;
+		this.exploratoryService = exploratoryService;
+		this.computationalService = computationalService;
+		this.securityService = securityService;
+		this.projectService = projectService;
+	}
+
+	@Override
+	public List<UserDTO> getUsers() {
+		final Set<String> activeUsers = envDAO.fetchActiveEnvUsers();
+		log.trace("Active users: {}", activeUsers);
+		final Set<String> notActiveUsers = envDAO.fetchUsersNotIn(activeUsers);
+		log.trace("Not active users: {}", notActiveUsers);
+		final Stream<UserDTO> activeUsersStream = activeUsers
+				.stream()
+				.map(u -> toUserDTO(u, ACTIVE));
+		final Stream<UserDTO> notActiveUsersStream = notActiveUsers
+				.stream()
+				.map(u -> toUserDTO(u, NOT_ACTIVE));
+		return Stream.concat(activeUsersStream, notActiveUsersStream)
+				.collect(toList());
+	}
+
+	@Override
+	public List<UserResourceInfo> getAllEnv(UserInfo user) {
+		log.debug("Getting all user's environment...");
+		List<UserInstanceDTO> expList = exploratoryDAO.getInstances();
+		return projectService.getProjects(user)
+				.stream()
+				.map(projectDTO -> getProjectEnv(projectDTO, expList))
+				.flatMap(Collection::stream)
+				.collect(toList());
+	}
+
+	@Override
+	public void stopAll() {
+		log.debug("Stopping environment for all users...");
+		projectService.getProjects()
+				.stream()
+				.map(ProjectDTO::getName)
+				.forEach(this::stopProjectEnvironment);
+	}
+
+	@Override
+	public void stopEnvironmentWithServiceAccount(String user) {
+		log.debug("Stopping environment for user {} by scheduler", user);
+		checkState(user, "stop");
+		exploratoryDAO.fetchRunningExploratoryFields(user)
+				.forEach(this::stopNotebookWithServiceAccount);
+	}
+
+	@Override
+	public void stopProjectEnvironment(String project) {
+		log.debug("Stopping environment for project {}", project);
+		checkProjectResourceConditions(project, "stop");
+		exploratoryDAO.fetchRunningExploratoryFieldsForProject(project)
+				.forEach(this::stopNotebookWithServiceAccount);
+
+		projectService.get(project).getEndpoints()
+				.stream()
+				.filter(e -> RUNNING == e.getStatus())
+				.forEach(endpoint -> projectService.stop(securityService.getServiceAccountInfo(DATALAB_SYSTEM_USER),
+						endpoint.getName(), project, AUDIT_QUOTA_MESSAGE));
+	}
+
+	@ProjectAdmin
+	@Override
+	public void stopExploratory(@User UserInfo userInfo, String user, @Project String project, String exploratoryName) {
+		exploratoryService.stop(userInfo, user, project, exploratoryName, null);
+	}
+
+	@ProjectAdmin
+	@Override
+	public void stopComputational(@User UserInfo userInfo, String user, @Project String project, String exploratoryName, String computationalName) {
+		computationalService.stopSparkCluster(userInfo, user, project, exploratoryName, computationalName,
+				String.format(AUDIT_MESSAGE, exploratoryName));
+	}
+
+	@ProjectAdmin
+	@Override
+	public void terminateExploratory(@User UserInfo userInfo, String user, @Project String project, String exploratoryName) {
+		exploratoryService.terminate(userInfo, user, project, exploratoryName, null);
+	}
+
+	@ProjectAdmin
+	@Override
+	public void terminateComputational(@User UserInfo userInfo, String user, @Project String project, String exploratoryName, String computationalName) {
+		computationalService.terminateComputational(userInfo, user, project, exploratoryName, computationalName, String.format(AUDIT_MESSAGE, exploratoryName));
+	}
+
+	private UserDTO toUserDTO(String u, UserDTO.Status status) {
+		return new UserDTO(u, settingsDAO.getAllowedBudget(u).orElse(null), status);
+	}
+
+	private void checkState(String user, String action) {
+		final List<UserInstanceDTO> userInstances = exploratoryDAO.fetchUserExploratoriesWhereStatusIn(user, Arrays.asList(CREATING, STARTING, CREATING_IMAGE),
+				CREATING, STARTING, CREATING_IMAGE);
+		if (!userInstances.isEmpty()) {
+			log.error(String.format(ERROR_MSG_FORMAT, action));
+			throw new ResourceConflictException(String.format(ERROR_MSG_FORMAT, action));
+		}
+	}
+
+	private void stopNotebookWithServiceAccount(UserInstanceDTO instance) {
+		final UserInfo userInfo = securityService.getServiceAccountInfo(DATALAB_SYSTEM_USER);
+		exploratoryService.stop(userInfo, instance.getUser(), instance.getProject(), instance.getExploratoryName(), AUDIT_QUOTA_MESSAGE);
+	}
+
+	private List<UserResourceInfo> getProjectEnv(ProjectDTO projectDTO, List<UserInstanceDTO> allInstances) {
+		final Stream<UserResourceInfo> userResources = allInstances
+				.stream()
+				.filter(instance -> instance.getProject().equals(projectDTO.getName()))
+				.map(this::toUserResourceInfo);
+		if (projectDTO.getEndpoints() != null) {
+			final Stream<UserResourceInfo> edges = projectDTO.getEndpoints()
+					.stream()
+					.map(e -> UserResourceInfo.builder()
+							.resourceType(ResourceEnum.EDGE_NODE)
+							.resourceStatus(e.getStatus().toString())
+							.project(projectDTO.getName())
+							.endpoint(e.getName())
+							.ip(e.getEdgeInfo() != null ? e.getEdgeInfo().getPublicIp() : null)
+							.build());
+			return Stream.concat(edges, userResources).collect(toList());
+		} else {
+			return userResources.collect(toList());
+		}
+	}
+
+	private UserResourceInfo toUserResourceInfo(UserInstanceDTO userInstance) {
+		return UserResourceInfo.builder()
+				.resourceType(ResourceEnum.NOTEBOOK)
+				.resourceName(userInstance.getExploratoryName())
+				.resourceShape(userInstance.getShape())
+				.resourceStatus(userInstance.getStatus())
+				.computationalResources(userInstance.getResources())
+				.user(userInstance.getUser())
+				.project(userInstance.getProject())
+				.endpoint(userInstance.getEndpoint())
+				.cloudProvider(userInstance.getCloudProvider())
+				.exploratoryUrls(userInstance.getResourceUrl())
+				.build();
+	}
+
+	private void checkProjectResourceConditions(String project, String action) {
+		final List<UserInstanceDTO> userInstances = exploratoryDAO.fetchProjectExploratoriesWhereStatusIn(project,
+				Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE);
+
+		if (!userInstances.isEmpty()) {
+			log.error(String.format(ERROR_MSG_FORMAT, action));
+			throw new ResourceConflictException(String.format(ERROR_MSG_FORMAT, action));
+		}
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ExploratoryServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ExploratoryServiceImpl.java
new file mode 100644
index 0000000..6ef627a
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ExploratoryServiceImpl.java
@@ -0,0 +1,467 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Audit;
+import com.epam.datalab.backendapi.annotation.BudgetLimited;
+import com.epam.datalab.backendapi.annotation.Info;
+import com.epam.datalab.backendapi.annotation.Project;
+import com.epam.datalab.backendapi.annotation.ResourceName;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.ComputationalDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.GitCredsDAO;
+import com.epam.datalab.backendapi.dao.ImageExploratoryDAO;
+import com.epam.datalab.backendapi.domain.AuditActionEnum;
+import com.epam.datalab.backendapi.domain.AuditDTO;
+import com.epam.datalab.backendapi.domain.AuditResourceTypeEnum;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.resources.dto.ExploratoryCreatePopUp;
+import com.epam.datalab.backendapi.service.AuditService;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.service.TagService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.StatusEnvBaseDTO;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.exploratory.ExploratoryActionDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryStatusDTO;
+import com.epam.datalab.dto.exploratory.LibInstallDTO;
+import com.epam.datalab.dto.exploratory.LibStatus;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.model.exploratory.Exploratory;
+import com.epam.datalab.model.library.Library;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.CREATE;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.RECONFIGURE;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.START;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.STOP;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.TERMINATE;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.NOTEBOOK;
+import static com.epam.datalab.dto.UserInstanceStatus.CREATING;
+import static com.epam.datalab.dto.UserInstanceStatus.FAILED;
+import static com.epam.datalab.dto.UserInstanceStatus.RUNNING;
+import static com.epam.datalab.dto.UserInstanceStatus.STARTING;
+import static com.epam.datalab.dto.UserInstanceStatus.STOPPED;
+import static com.epam.datalab.dto.UserInstanceStatus.STOPPING;
+import static com.epam.datalab.dto.UserInstanceStatus.TERMINATED;
+import static com.epam.datalab.dto.UserInstanceStatus.TERMINATING;
+import static com.epam.datalab.rest.contracts.ExploratoryAPI.EXPLORATORY_CREATE;
+import static com.epam.datalab.rest.contracts.ExploratoryAPI.EXPLORATORY_RECONFIGURE_SPARK;
+import static com.epam.datalab.rest.contracts.ExploratoryAPI.EXPLORATORY_START;
+import static com.epam.datalab.rest.contracts.ExploratoryAPI.EXPLORATORY_STOP;
+import static com.epam.datalab.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;
+    private final AuditService auditService;
+    private final SelfServiceApplicationConfiguration configuration;
+
+    @Inject
+    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, AuditService auditService,
+                                  SelfServiceApplicationConfiguration configuration) {
+        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;
+        this.auditService = auditService;
+        this.configuration = configuration;
+    }
+
+    @BudgetLimited
+    @Audit(action = START, type = NOTEBOOK)
+    @Override
+    public String start(@User UserInfo userInfo, @ResourceName String exploratoryName, @Project String project, @Info String auditInfo) {
+        return action(userInfo, userInfo.getName(), project, exploratoryName, EXPLORATORY_START, STARTING);
+    }
+
+    @Audit(action = STOP, type = NOTEBOOK)
+    @Override
+    public String stop(@User UserInfo userInfo, String resourceCreator, @Project String project, @ResourceName String exploratoryName, @Info String auditInfo) {
+        return action(userInfo, resourceCreator, project, exploratoryName, EXPLORATORY_STOP, STOPPING);
+    }
+
+    @Audit(action = TERMINATE, type = NOTEBOOK)
+    @Override
+    public String terminate(@User UserInfo userInfo, String resourceCreator, @Project String project, @ResourceName String exploratoryName, @Info String auditInfo) {
+        return action(userInfo, resourceCreator, project, exploratoryName, EXPLORATORY_TERMINATE, TERMINATING);
+    }
+
+    @BudgetLimited
+    @Audit(action = CREATE, type = NOTEBOOK)
+    @Override
+    public String create(@User UserInfo userInfo, Exploratory exploratory, @Project String project, @ResourceName String exploratoryName) {
+        boolean isAdded = false;
+        try {
+            final ProjectDTO projectDTO = projectService.get(project);
+            final EndpointDTO endpointDTO = endpointService.get(exploratory.getEndpoint());
+            final UserInstanceDTO userInstanceDTO = getUserInstanceDTO(userInfo, exploratory, project, endpointDTO.getCloudProvider());
+            exploratoryDAO.insertExploratory(userInstanceDTO);
+            isAdded = true;
+            final ExploratoryGitCredsDTO gitCreds = gitCredsDAO.findGitCreds(userInfo.getName());
+            log.debug("Created exploratory environment {} for user {}", exploratory.getName(), userInfo.getName());
+            final String uuid =
+                    provisioningService.post(endpointDTO.getUrl() + EXPLORATORY_CREATE,
+                            userInfo.getAccessToken(),
+                            requestBuilder.newExploratoryCreate(projectDTO, endpointDTO, exploratory, userInfo,
+                                    gitCreds, userInstanceDTO.getTags()),
+                            String.class);
+            requestId.put(userInfo.getName(), uuid);
+            return uuid;
+        } catch (Exception t) {
+            log.error("Could not update the status of exploratory environment {} with name {} for user {}",
+                    exploratory.getDockerImage(), exploratory.getName(), userInfo.getName(), t);
+            if (isAdded) {
+                updateExploratoryStatusSilent(userInfo.getName(), project, exploratory.getName(), FAILED);
+            }
+            throw new DatalabException("Could not create exploratory environment " + exploratory.getName() + " for user "
+                    + userInfo.getName() + ": " + Optional.ofNullable(t.getCause()).map(Throwable::getMessage).orElse(t.getMessage()), t);
+        }
+    }
+
+    @Override
+    public void updateProjectExploratoryStatuses(UserInfo userInfo, String project, String endpoint, UserInstanceStatus status) {
+        exploratoryDAO.fetchProjectExploratoriesWhereStatusNotIn(project, endpoint, TERMINATED, FAILED)
+                .forEach(ui -> updateExploratoryComputeStatuses(userInfo, project, ui.getExploratoryName(), status, ui.getUser()));
+    }
+
+    @Override
+    public void updateProjectExploratoryStatuses(String project, String endpoint, UserInstanceStatus status) {
+        exploratoryDAO.fetchProjectExploratoriesWhereStatusNotIn(project, endpoint, TERMINATED, FAILED)
+                .forEach(ui -> {
+                    updateExploratoryStatus(ui.getUser(), project, ui.getExploratoryName(), status);
+                    updateComputationalStatuses(ui.getUser(), project, ui.getExploratoryName(), TERMINATED, TERMINATED, TERMINATED, FAILED);
+                });
+    }
+
+    @Audit(action = RECONFIGURE, type = NOTEBOOK)
+    @Override
+    public void updateClusterConfig(@User UserInfo userInfo, @Project 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);
+        EndpointDTO endpointDTO = endpointService.get(userInstanceDTO.getEndpoint());
+        final ExploratoryReconfigureSparkClusterActionDTO updateClusterConfigDTO =
+                requestBuilder.newClusterConfigUpdate(userInfo, userInstanceDTO, config, endpointDTO);
+        final String uuid = provisioningService.post(endpointDTO.getUrl() + EXPLORATORY_RECONFIGURE_SPARK,
+                token, updateClusterConfigDTO,
+                String.class);
+        requestId.put(userName, uuid);
+        exploratoryDAO.updateExploratoryFields(new ExploratoryStatusDTO()
+                .withUser(userName)
+                .withProject(project)
+                .withExploratoryName(exploratoryName)
+                .withConfig(config)
+                .withStatus(UserInstanceStatus.RECONFIGURING.toString()));
+    }
+
+    /**
+     * Returns user instance's data by it's name.
+     *
+     * @param user            user.
+     * @param project
+     * @param exploratoryName name of exploratory.
+     * @return corresponding user instance's data or empty data if resource doesn't exist.
+     */
+    @Override
+    public Optional<UserInstanceDTO> getUserInstance(String user, String project, String exploratoryName) {
+        try {
+            return Optional.of(exploratoryDAO.fetchExploratoryFields(user, project, exploratoryName));
+        } catch (DatalabException e) {
+            log.warn("User instance with exploratory {}, project {} for user {} not found.", exploratoryName, project, user, e);
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public Optional<UserInstanceDTO> getUserInstance(String user, String project, String exploratoryName, boolean includeCompResources) {
+        try {
+            return Optional.of(exploratoryDAO.fetchExploratoryFields(user, project, exploratoryName, includeCompResources));
+        } catch (DatalabException e) {
+            log.warn("User instance with exploratory {}, project {} for user {} not found.", exploratoryName, project, user, e);
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public List<UserInstanceDTO> findAll() {
+        return exploratoryDAO.getInstances();
+    }
+
+    @Override
+    public List<UserInstanceDTO> findAll(Set<ProjectDTO> projects) {
+        List<String> projectNames = projects
+                .stream()
+                .map(ProjectDTO::getName)
+                .collect(Collectors.toList());
+        return exploratoryDAO.fetchExploratoryFieldsForProjectWithComp(projectNames);
+    }
+
+    @Override
+    public List<ClusterConfig> getClusterConfig(UserInfo user, String project, String exploratoryName) {
+        return exploratoryDAO.getClusterConfig(user.getName(), project, exploratoryName);
+    }
+
+    @Override
+    public ExploratoryCreatePopUp getUserInstances(UserInfo user) {
+        List<ProjectDTO> userProjects = projectService.getUserProjects(user, false);
+        Map<String, List<String>> collect = userProjects.stream()
+                .collect(Collectors.toMap(ProjectDTO::getName, this::getProjectExploratoryNames));
+        return new ExploratoryCreatePopUp(userProjects, collect);
+    }
+
+    private List<String> getProjectExploratoryNames(ProjectDTO project) {
+        return exploratoryDAO.fetchExploratoryFieldsForProject(project.getName()).stream()
+                .map(UserInstanceDTO::getExploratoryName)
+                .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 resourceCreator, String project, String exploratoryName, String action, UserInstanceStatus status) {
+        try {
+            updateExploratoryComputeStatuses(userInfo.getName(), project, exploratoryName, status, resourceCreator);
+
+            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, 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, 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()));
+            throw new DatalabException(errorMsg, t);
+        }
+    }
+
+    @Audit(action = TERMINATE, type = NOTEBOOK)
+    public void updateExploratoryComputeStatuses(@User UserInfo userInfo, @Project String project, @ResourceName String exploratoryName, UserInstanceStatus status, String resourceCreator) {
+        updateExploratoryStatus(resourceCreator, project, exploratoryName, status);
+        updateComputationalStatuses(userInfo.getName(), resourceCreator, project, exploratoryName, status);
+    }
+
+    private void updateExploratoryComputeStatuses(String user, String project, String exploratoryName, UserInstanceStatus status, String resourceCreator) {
+        updateExploratoryStatus(resourceCreator, project, exploratoryName, status);
+        updateComputationalStatuses(user, resourceCreator, project, exploratoryName, status);
+    }
+
+    private void updateComputationalStatuses(String user, String resourceCreator, String project, String exploratoryName, UserInstanceStatus status) {
+        if (status == STOPPING) {
+            if (configuration.isAuditEnabled()) {
+                saveAudit(user, resourceCreator, project, exploratoryName, STOP, RUNNING);
+            }
+            updateComputationalStatuses(resourceCreator, project, exploratoryName, STOPPING, TERMINATING, FAILED, TERMINATED, STOPPED);
+        } else if (status == TERMINATING) {
+            if (configuration.isAuditEnabled()) {
+                saveAudit(user, resourceCreator, project, exploratoryName, TERMINATE, RUNNING, STOPPED);
+            }
+            updateComputationalStatuses(resourceCreator, project, exploratoryName, TERMINATING, TERMINATING, TERMINATED, FAILED);
+        }
+    }
+
+    private void saveAudit(String user, String resourceCreator, String project, String exploratoryName, AuditActionEnum action, UserInstanceStatus... sparkStatuses) {
+        saveAuditForComputational(user, resourceCreator, project, exploratoryName, action, DataEngineType.SPARK_STANDALONE, sparkStatuses);
+        saveAuditForComputational(user, resourceCreator, project, exploratoryName, TERMINATE, DataEngineType.CLOUD_SERVICE, RUNNING, STOPPED);
+    }
+
+    private void saveAuditForComputational(String user, String resourceCreator, String project, String exploratoryName, AuditActionEnum action, DataEngineType cloudService,
+                                           UserInstanceStatus... computationalStatuses) {
+        computationalDAO.getComputationalResourcesWhereStatusIn(resourceCreator, project, Collections.singletonList(cloudService),
+                exploratoryName, computationalStatuses)
+                .forEach(comp -> auditService.save(
+                        AuditDTO.builder()
+                                .user(user)
+                                .resourceName(comp)
+                                .project(project)
+                                .action(action)
+                                .type(AuditResourceTypeEnum.COMPUTE)
+                                .build())
+                );
+    }
+
+    private ExploratoryActionDTO<?> getExploratoryActionDto(UserInfo userInfo, String resourceCreator, UserInstanceStatus status, UserInstanceDTO userInstance,
+                                                            EndpointDTO endpointDTO) {
+        ExploratoryActionDTO<?> dto;
+        if (status != UserInstanceStatus.STARTING) {
+            dto = requestBuilder.newExploratoryStop(resourceCreator, userInstance, endpointDTO);
+        } else {
+            dto = requestBuilder.newExploratoryStart(userInfo, userInstance, endpointDTO, gitCredsDAO.findGitCreds(userInfo.getName()));
+        }
+        return dto;
+    }
+
+
+    /**
+     * Updates the status of exploratory environment.
+     *
+     * @param user            user name
+     * @param project         project name
+     * @param exploratoryName name of exploratory environment.
+     * @param status          status for exploratory environment.
+     */
+    private void updateExploratoryStatus(String user, String project, String exploratoryName, UserInstanceStatus status) {
+        StatusEnvBaseDTO<?> exploratoryStatus = createStatusDTO(user, project, exploratoryName, status);
+        exploratoryDAO.updateExploratoryStatus(exploratoryStatus);
+    }
+
+    /**
+     * Updates the status of exploratory environment without exceptions. If exception occurred then logging it.
+     *
+     * @param user            user name
+     * @param project         project name
+     * @param exploratoryName name of exploratory environment.
+     * @param status          status for exploratory environment.
+     */
+    private void updateExploratoryStatusSilent(String user, String project, String exploratoryName, UserInstanceStatus status) {
+        try {
+            updateExploratoryStatus(user, project, exploratoryName, status);
+        } catch (DatalabException e) {
+            log.error("Could not update the status of exploratory environment {} for user {} to {}",
+                    exploratoryName, user, status, e);
+        }
+    }
+
+    private void updateComputationalStatuses(String user, String project, String exploratoryName, UserInstanceStatus
+            dataEngineStatus, UserInstanceStatus dataEngineServiceStatus, UserInstanceStatus... excludedStatuses) {
+        log.debug("updating status for all computational resources of {} for user {}: DataEngine {}, " +
+                "dataengine-service {}", exploratoryName, user, dataEngineStatus, dataEngineServiceStatus);
+        computationalDAO.updateComputationalStatusesForExploratory(user, project, exploratoryName,
+                dataEngineStatus, dataEngineServiceStatus, excludedStatuses);
+    }
+
+    /**
+     * Instantiates and returns the descriptor of exploratory environment status.
+     *
+     * @param user            user name
+     * @param project         project
+     * @param exploratoryName name of exploratory environment.
+     * @param status          status for exploratory environment.
+     */
+    private StatusEnvBaseDTO<?> createStatusDTO(String user, String project, String exploratoryName, UserInstanceStatus status) {
+        return new ExploratoryStatusDTO()
+                .withUser(user)
+                .withProject(project)
+                .withExploratoryName(exploratoryName)
+                .withStatus(status);
+    }
+
+    private UserInstanceDTO getUserInstanceDTO(UserInfo userInfo, Exploratory exploratory, String project, CloudProvider cloudProvider) {
+        final UserInstanceDTO userInstance = new UserInstanceDTO()
+                .withUser(userInfo.getName())
+                .withExploratoryName(exploratory.getName())
+                .withStatus(CREATING.toString())
+                .withImageName(exploratory.getDockerImage())
+                .withImageVersion(exploratory.getVersion())
+                .withTemplateName(exploratory.getTemplateName())
+                .withClusterConfig(exploratory.getClusterConfig())
+                .withShape(exploratory.getShape())
+                .withProject(project)
+                .withEndpoint(exploratory.getEndpoint())
+                .withCloudProvider(cloudProvider.toString())
+                .withTags(tagService.getResourceTags(userInfo, exploratory.getEndpoint(), project,
+                        exploratory.getExploratoryTag()));
+        if (StringUtils.isNotBlank(exploratory.getImageName())) {
+            final List<LibInstallDTO> libInstallDtoList = getImageRelatedLibraries(userInfo, exploratory.getImageName(),
+                    project, exploratory.getEndpoint());
+            userInstance.withLibs(libInstallDtoList);
+        }
+        return userInstance;
+    }
+
+    private List<LibInstallDTO> getImageRelatedLibraries(UserInfo userInfo, String imageFullName, String project,
+                                                         String endpoint) {
+        final List<Library> libraries = imageExploratoryDao.getLibraries(userInfo.getName(), imageFullName, project,
+                endpoint, LibStatus.INSTALLED);
+        return toLibInstallDtoList(libraries);
+    }
+
+    private List<LibInstallDTO> toLibInstallDtoList(List<Library> libraries) {
+        return libraries
+                .stream()
+                .map(this::toLibInstallDto)
+                .collect(Collectors.toList());
+    }
+
+    private LibInstallDTO toLibInstallDto(Library l) {
+        return new LibInstallDTO(l.getGroup(), l.getName(), l.getVersion())
+                .withStatus(String.valueOf(l.getStatus()))
+                .withAddedPackages(l.getAddedPackages())
+                .withErrorMessage(l.getErrorMessage());
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/GitCredentialServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/GitCredentialServiceImpl.java
new file mode 100644
index 0000000..a8540ac
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/GitCredentialServiceImpl.java
@@ -0,0 +1,119 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Audit;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.GitCredsDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.GitCredentialService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.UPDATE;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.GIT_ACCOUNT;
+import static com.epam.datalab.rest.contracts.ExploratoryAPI.EXPLORATORY_GIT_CREDS;
+
+@Slf4j
+@Singleton
+public class GitCredentialServiceImpl implements GitCredentialService {
+
+    private static final boolean CLEAR_USER_PASSWORD = true;
+    @Inject
+    private GitCredsDAO gitCredsDAO;
+    @Inject
+    private ExploratoryDAO exploratoryDAO;
+    @Inject
+    @Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
+    private RESTService provisioningService;
+    @Inject
+    private RequestBuilder requestBuilder;
+    @Inject
+    private RequestId requestId;
+    @Inject
+    private EndpointService endpointService;
+
+    @Audit(action = UPDATE, type = GIT_ACCOUNT)
+    @Override
+    public void updateGitCredentials(@User UserInfo userInfo, ExploratoryGitCredsDTO formDTO) {
+        log.debug("Updating GIT creds for user {} to {}", userInfo.getName(), formDTO);
+        try {
+            gitCredsDAO.updateGitCreds(userInfo.getName(), formDTO);
+            final String failedNotebooks = exploratoryDAO.fetchRunningExploratoryFields(userInfo.getName())
+                    .stream()
+                    .filter(ui -> !updateNotebookGitCredentials(userInfo, formDTO, ui))
+                    .map(UserInstanceDTO::getExploratoryName)
+                    .collect(Collectors.joining(","));
+            if (StringUtils.isNotEmpty(failedNotebooks)) {
+                throw new DatalabException("Requests for notebooks failed: " + failedNotebooks);
+            }
+        } catch (Exception t) {
+            log.error("Cannot update the GIT creds for user {}", userInfo.getName(), t);
+            throw new DatalabException("Cannot update the GIT credentials: " + t.getLocalizedMessage(), t);
+        }
+    }
+
+    @Override
+    public ExploratoryGitCredsDTO getGitCredentials(String user) {
+        log.debug("Loading GIT creds for user {}", user);
+        try {
+            return gitCredsDAO.findGitCreds(user, CLEAR_USER_PASSWORD);
+        } catch (Exception t) {
+            log.error("Cannot load list of GIT creds for user: {}", user, t);
+            throw new DatalabException(String.format("Cannot load GIT credentials for user %s: %s",
+                    user, t.getLocalizedMessage()), t);
+        }
+    }
+
+    private boolean updateNotebookGitCredentials(UserInfo userInfo, ExploratoryGitCredsDTO formDTO,
+                                                 UserInstanceDTO instance) {
+        boolean gitCredentialsUpdated = true;
+        try {
+            log.debug("Updating GIT creds for user {} on exploratory {}",
+                    userInfo.getName(), instance.getExploratoryName());
+            EndpointDTO endpointDTO = endpointService.get(instance.getEndpoint());
+            ExploratoryGitCredsUpdateDTO dto = requestBuilder.newGitCredentialsUpdate(userInfo, instance, endpointDTO, formDTO);
+            final String uuid = provisioningService.post(endpointDTO.getUrl() + EXPLORATORY_GIT_CREDS,
+                    userInfo.getAccessToken(), dto, String.class);
+            requestId.put(userInfo.getName(), uuid);
+        } catch (Exception t) {
+            log.error("Cannot update the GIT creds for user {} on exploratory {}", userInfo.getName(),
+                    instance.getExploratoryName(), t);
+            gitCredentialsUpdated = false;
+        }
+        return gitCredentialsUpdated;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/GuacamoleServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/GuacamoleServiceImpl.java
new file mode 100644
index 0000000..80534fe
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/GuacamoleServiceImpl.java
@@ -0,0 +1,91 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.GuacamoleService;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.KeyAPI;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.guacamole.net.GuacamoleTunnel;
+import org.apache.guacamole.net.InetGuacamoleSocket;
+import org.apache.guacamole.net.SimpleGuacamoleTunnel;
+import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+
+import javax.inject.Named;
+import java.net.URI;
+import java.util.Map;
+
+@Slf4j
+@Singleton
+public class GuacamoleServiceImpl implements GuacamoleService {
+
+    private static final String PRIVATE_KEY_PARAM_NAME = "private-key";
+    private static final String HOSTNAME_PARAM = "hostname";
+    private static final String CONNECTION_PROTOCOL_PARAM = "connectionProtocol";
+    private static final String SERVER_HOST_PARAM = "serverHost";
+    private final SelfServiceApplicationConfiguration conf;
+    private final RESTService provisioningService;
+    private final EndpointService endpointService;
+
+    @Inject
+    public GuacamoleServiceImpl(SelfServiceApplicationConfiguration conf,
+                                @Named(ServiceConsts.PROVISIONING_SERVICE_NAME) RESTService provisioningService,
+                                EndpointService endpointService) {
+        this.conf = conf;
+        this.provisioningService = provisioningService;
+        this.endpointService = endpointService;
+    }
+
+    @Override
+    public GuacamoleTunnel getTunnel(UserInfo userInfo, String host, String endpoint) {
+        try {
+            final String url = endpointService.get(endpoint).getUrl();
+            String key = provisioningService.get(url + KeyAPI.GET_ADMIN_KEY,
+                    userInfo.getAccessToken(), String.class);
+            final String guacamoleServerHost = new URI(url).getHost();
+            InetGuacamoleSocket socket = new InetGuacamoleSocket(guacamoleServerHost, conf.getGuacamolePort());
+            final Map<String, String> guacamoleConf = conf.getGuacamole();
+            guacamoleConf.put(SERVER_HOST_PARAM, guacamoleServerHost);
+            GuacamoleConfiguration guacamoleConfig = getGuacamoleConfig(key, guacamoleConf, host);
+            return new SimpleGuacamoleTunnel(new ConfiguredGuacamoleSocket(socket, guacamoleConfig));
+        } catch (Exception e) {
+            log.error("Can not create guacamole tunnel due to: " + e.getMessage());
+            throw new DatalabException("Can not create guacamole tunnel due to: " + e.getMessage(), e);
+        }
+    }
+
+    private GuacamoleConfiguration getGuacamoleConfig(String privateKeyContent, Map<String, String> guacamoleParams,
+                                                      String host) {
+        GuacamoleConfiguration guacamoleConfiguration = new GuacamoleConfiguration();
+        guacamoleConfiguration.setProtocol(guacamoleParams.get(CONNECTION_PROTOCOL_PARAM));
+        guacamoleConfiguration.setParameters(guacamoleParams);
+        guacamoleConfiguration.setParameter(HOSTNAME_PARAM, host);
+        guacamoleConfiguration.setParameter(PRIVATE_KEY_PARAM_NAME, privateKeyContent);
+        return guacamoleConfiguration;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImpl.java
new file mode 100644
index 0000000..8c68021
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImpl.java
@@ -0,0 +1,177 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Audit;
+import com.epam.datalab.backendapi.annotation.Info;
+import com.epam.datalab.backendapi.annotation.Project;
+import com.epam.datalab.backendapi.annotation.ResourceName;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryLibDAO;
+import com.epam.datalab.backendapi.dao.ImageExploratoryDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.ImageExploratoryService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.exploratory.ExploratoryStatusDTO;
+import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.epam.datalab.exceptions.ResourceAlreadyExistException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.model.ResourceType;
+import com.epam.datalab.model.exploratory.Image;
+import com.epam.datalab.model.library.Library;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.ExploratoryAPI;
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.CREATE;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.IMAGE;
+
+@Singleton
+@Slf4j
+public class ImageExploratoryServiceImpl implements ImageExploratoryService {
+    private static final String IMAGE_EXISTS_MSG = "Image with name %s is already exist in project %s";
+    private static final String IMAGE_NOT_FOUND_MSG = "Image with name %s was not found for user %s";
+
+    @Inject
+    private ExploratoryDAO exploratoryDAO;
+    @Inject
+    private ImageExploratoryDAO imageExploratoryDao;
+    @Inject
+    private ExploratoryLibDAO libDAO;
+    @Inject
+    @Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
+    private RESTService provisioningService;
+    @Inject
+    private RequestBuilder requestBuilder;
+    @Inject
+    private EndpointService endpointService;
+    @Inject
+    private ProjectService projectService;
+
+    @Audit(action = CREATE, type = IMAGE)
+    @Override
+    public String createImage(@User UserInfo user, @Project String project, @ResourceName String exploratoryName, String imageName, String imageDescription, @Info String info) {
+        ProjectDTO projectDTO = projectService.get(project);
+        UserInstanceDTO userInstance = exploratoryDAO.fetchRunningExploratoryFields(user.getName(), project, exploratoryName);
+
+        if (imageExploratoryDao.exist(imageName, userInstance.getProject())) {
+            log.error(String.format(IMAGE_EXISTS_MSG, imageName, userInstance.getProject()));
+            throw new ResourceAlreadyExistException(String.format(IMAGE_EXISTS_MSG, imageName, userInstance.getProject()));
+        }
+        final List<Library> libraries = libDAO.getLibraries(user.getName(), project, exploratoryName);
+
+        imageExploratoryDao.save(Image.builder()
+                .name(imageName)
+                .description(imageDescription)
+                .status(ImageStatus.CREATING)
+                .user(user.getName())
+                .libraries(fetchExploratoryLibs(libraries))
+                .computationalLibraries(fetchComputationalLibs(libraries))
+                .dockerImage(userInstance.getImageName())
+                .exploratoryId(userInstance.getId())
+                .project(userInstance.getProject())
+                .endpoint(userInstance.getEndpoint())
+                .build());
+
+        exploratoryDAO.updateExploratoryStatus(new ExploratoryStatusDTO()
+                .withUser(user.getName())
+                .withProject(project)
+                .withExploratoryName(exploratoryName)
+                .withStatus(UserInstanceStatus.CREATING_IMAGE));
+
+        EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
+        return provisioningService.post(endpointDTO.getUrl() + ExploratoryAPI.EXPLORATORY_IMAGE,
+                user.getAccessToken(),
+                requestBuilder.newExploratoryImageCreate(user, userInstance, imageName, endpointDTO, projectDTO), String.class);
+    }
+
+    @Override
+    public void finishImageCreate(Image image, String exploratoryName, String newNotebookIp) {
+        log.debug("Returning exploratory status with name {} to RUNNING for user {}",
+                exploratoryName, image.getUser());
+        exploratoryDAO.updateExploratoryStatus(new ExploratoryStatusDTO()
+                .withUser(image.getUser())
+                .withProject(image.getProject())
+                .withExploratoryName(exploratoryName)
+                .withStatus(UserInstanceStatus.RUNNING));
+        imageExploratoryDao.updateImageFields(image);
+        if (newNotebookIp != null) {
+            log.debug("Changing exploratory ip with name {} for user {} to {}", exploratoryName, image.getUser(),
+                    newNotebookIp);
+            exploratoryDAO.updateExploratoryIp(image.getUser(), image.getProject(), newNotebookIp, exploratoryName);
+        }
+
+    }
+
+    @Override
+    public List<ImageInfoRecord> getNotFailedImages(String user, String dockerImage, String project, String endpoint) {
+        return imageExploratoryDao.getImages(user, dockerImage, project, endpoint, ImageStatus.CREATED, ImageStatus.CREATING);
+    }
+
+    @Override
+    public ImageInfoRecord getImage(String user, String name, String project, String endpoint) {
+        return imageExploratoryDao.getImage(user, name, project, endpoint).orElseThrow(() ->
+                new ResourceNotFoundException(String.format(IMAGE_NOT_FOUND_MSG, name, user)));
+    }
+
+    @Override
+    public List<ImageInfoRecord> getImagesForProject(String project) {
+        return imageExploratoryDao.getImagesForProject(project);
+    }
+
+    private Map<String, List<Library>> fetchComputationalLibs(List<Library> libraries) {
+        return libraries.stream()
+                .filter(resourceTypePredicate(ResourceType.COMPUTATIONAL))
+                .collect(Collectors.toMap(Library::getResourceName, Lists::newArrayList, this::merge));
+    }
+
+    private List<Library> merge(List<Library> oldValue, List<Library> newValue) {
+        oldValue.addAll(newValue);
+        return oldValue;
+    }
+
+    private List<Library> fetchExploratoryLibs(List<Library> libraries) {
+        return libraries.stream()
+                .filter(resourceTypePredicate(ResourceType.EXPLORATORY))
+                .collect(Collectors.toList());
+    }
+
+    private Predicate<Library> resourceTypePredicate(ResourceType resourceType) {
+        return l -> resourceType == l.getType();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InactivityServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InactivityServiceImpl.java
new file mode 100644
index 0000000..96fb050
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InactivityServiceImpl.java
@@ -0,0 +1,111 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.ComputationalDAO;
+import com.epam.datalab.backendapi.dao.EnvDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.InactivityService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.computational.ComputationalCheckInactivityDTO;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.dto.exploratory.ExploratoryCheckInactivityAction;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.InfrasctructureAPI;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+
+import java.time.LocalDateTime;
+
+@Slf4j
+public class InactivityServiceImpl implements InactivityService {
+    @Inject
+    private ExploratoryDAO exploratoryDAO;
+    @Inject
+    private ComputationalDAO computationalDAO;
+    @Inject
+    private EnvDAO envDAO;
+    @Inject
+    private RequestBuilder requestBuilder;
+    @Inject
+    @Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
+    private RESTService provisioningService;
+    @Inject
+    private RequestId requestId;
+    @Inject
+    private SecurityService securityService;
+    @Inject
+    private EndpointService endpointService;
+
+    @Override
+    public void updateRunningResourcesLastActivity() {
+        envDAO.findRunningResourcesForCheckInactivity()
+                .forEach(this::updateLastActivity);
+    }
+
+    @Override
+    public void updateLastActivityForExploratory(UserInfo userInfo, String exploratoryName,
+                                                 LocalDateTime lastActivity) {
+        exploratoryDAO.updateLastActivity(userInfo.getName(), exploratoryName, lastActivity);
+    }
+
+    @Override
+    public void updateLastActivityForComputational(UserInfo userInfo, String project, String exploratoryName,
+                                                   String computationalName, LocalDateTime lastActivity) {
+        computationalDAO.updateLastActivity(userInfo.getName(), project, exploratoryName, computationalName, lastActivity);
+    }
+
+    private void updateLastActivity(UserInstanceDTO ui) {
+        if (UserInstanceStatus.RUNNING.toString().equals(ui.getStatus())) {
+            updateExploratoryLastActivity(securityService.getUserInfoOffline(ui.getUser()), ui);
+        }
+        ui.getResources()
+                .stream()
+                .filter(comp -> UserInstanceStatus.RUNNING.toString().equals(comp.getStatus()))
+                .forEach(cr -> updateComputationalLastActivity(securityService.getUserInfoOffline(ui.getUser()), ui, cr));
+    }
+
+    private void updateComputationalLastActivity(UserInfo userInfo, UserInstanceDTO ui, UserComputationalResource cr) {
+        EndpointDTO endpointDTO = endpointService.get(ui.getEndpoint());
+        final ComputationalCheckInactivityDTO dto = requestBuilder.newComputationalCheckInactivity(userInfo, ui, cr, endpointDTO);
+        final String uuid =
+                provisioningService.post(endpointDTO.getUrl() + InfrasctructureAPI.COMPUTATIONAL_CHECK_INACTIVITY,
+                        userInfo.getAccessToken(), dto, String.class);
+        requestId.put(userInfo.getName(), uuid);
+    }
+
+    private void updateExploratoryLastActivity(UserInfo userInfo, UserInstanceDTO ui) {
+        EndpointDTO endpointDTO = endpointService.get(ui.getEndpoint());
+        final ExploratoryCheckInactivityAction dto =
+                requestBuilder.newExploratoryCheckInactivityAction(userInfo, ui, endpointDTO);
+        final String uuid =
+                provisioningService.post(endpointDTO.getUrl() + InfrasctructureAPI.EXPLORATORY_CHECK_INACTIVITY,
+                        userInfo.getAccessToken(), dto, String.class);
+        requestId.put(userInfo.getName(), uuid);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImpl.java
new file mode 100644
index 0000000..f01be38
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImpl.java
@@ -0,0 +1,193 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.domain.BillingReport;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectEndpointDTO;
+import com.epam.datalab.backendapi.resources.dto.HealthStatusEnum;
+import com.epam.datalab.backendapi.resources.dto.HealthStatusPageDTO;
+import com.epam.datalab.backendapi.resources.dto.ProjectInfrastructureInfo;
+import com.epam.datalab.backendapi.roles.RoleType;
+import com.epam.datalab.backendapi.roles.UserRoles;
+import com.epam.datalab.backendapi.service.BillingService;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.InfrastructureInfoService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.dto.InfrastructureMetaInfoDTO;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.aws.edge.EdgeInfoAws;
+import com.epam.datalab.dto.azure.edge.EdgeInfoAzure;
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.dto.gcp.edge.EdgeInfoGcp;
+import com.google.inject.Inject;
+import com.jcabi.manifests.Manifests;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class InfrastructureInfoServiceImpl implements InfrastructureInfoService {
+	private static final String RELEASE_NOTES_FORMAT = "https://github.com/apache/incubator-dlab/blob/%s/RELEASE_NOTES.md";
+	private static final String PERMISSION_VIEW = "/api/bucket/view";
+	private static final String PERMISSION_UPLOAD = "/api/bucket/upload";
+	private static final String PERMISSION_DOWNLOAD = "/api/bucket/download";
+	private static final String PERMISSION_DELETE = "/api/bucket/delete";
+
+	private final ExploratoryDAO expDAO;
+	private final SelfServiceApplicationConfiguration configuration;
+	private final ProjectService projectService;
+	private final EndpointService endpointService;
+	private final BillingService billingService;
+
+	@Inject
+	public InfrastructureInfoServiceImpl(ExploratoryDAO expDAO, SelfServiceApplicationConfiguration configuration, ProjectService projectService,
+										 EndpointService endpointService, BillingService billingService) {
+		this.expDAO = expDAO;
+		this.configuration = configuration;
+		this.projectService = projectService;
+		this.endpointService = endpointService;
+		this.billingService = billingService;
+	}
+
+	@Override
+	public List<ProjectInfrastructureInfo> getUserResources(UserInfo user) {
+		log.debug("Loading list of provisioned resources for user {}", user);
+		List<EndpointDTO> allEndpoints = endpointService.getEndpoints();
+		return projectService.getUserProjects(user, Boolean.FALSE)
+				.stream()
+				.map(p -> {
+					List<UserInstanceDTO> exploratories = expDAO.findExploratories(user.getName(), p.getName());
+					return ProjectInfrastructureInfo.builder()
+							.project(p.getName())
+							.billingQuoteUsed(billingService.getBillingProjectQuoteUsed(p.getName()))
+							.shared(getSharedInfo(p.getName()))
+							.exploratory(exploratories)
+							.exploratoryBilling(getExploratoryBillingData(exploratories))
+							.endpoints(getEndpoints(allEndpoints, p))
+							.build();
+				})
+				.collect(Collectors.toList());
+	}
+
+	@Override
+	public HealthStatusPageDTO getHeathStatus(UserInfo userInfo) {
+		log.debug("Request the status of resources for user {}", userInfo.getName());
+		return HealthStatusPageDTO.builder()
+				.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))
+				.bucketBrowser(HealthStatusPageDTO.BucketBrowser.builder()
+						.view(checkAccess(userInfo, PERMISSION_VIEW))
+						.upload(checkAccess(userInfo, PERMISSION_UPLOAD))
+						.download(checkAccess(userInfo, PERMISSION_DOWNLOAD))
+						.delete(checkAccess(userInfo, PERMISSION_DELETE))
+						.build())
+				.build();
+	}
+
+	@Override
+	public InfrastructureMetaInfoDTO getInfrastructureMetaInfo() {
+		final String branch = Manifests.read("GIT-Branch");
+		return InfrastructureMetaInfoDTO.builder()
+				.branch(branch)
+				.commit(Manifests.read("GIT-Commit"))
+				.version(Manifests.read("DataLab-Version"))
+				.releaseNotes(String.format(RELEASE_NOTES_FORMAT, branch))
+				.build();
+	}
+
+	private List<BillingReport> getExploratoryBillingData(List<UserInstanceDTO> exploratories) {
+		return exploratories
+				.stream()
+				.map(exp -> billingService.getExploratoryBillingData(exp.getProject(), exp.getEndpoint(),
+						exp.getExploratoryName(), exp.getResources()
+								.stream()
+								.map(UserComputationalResource::getComputationalName)
+								.collect(Collectors.toList())
+				))
+				.collect(Collectors.toList());
+	}
+
+	private List<EndpointDTO> getEndpoints(List<EndpointDTO> allEndpoints, ProjectDTO projectDTO) {
+		return allEndpoints
+				.stream()
+				.filter(endpoint -> projectDTO.getEndpoints()
+						.stream()
+						.anyMatch(endpoint1 -> endpoint1.getName().equals(endpoint.getName())))
+				.collect(Collectors.toList());
+	}
+
+	private Map<String, Map<String, String>> getSharedInfo(String name) {
+		return projectService.get(name).getEndpoints()
+				.stream()
+				.collect(Collectors.toMap(ProjectEndpointDTO::getName, this::getSharedInfo));
+	}
+
+	private Map<String, String> getSharedInfo(ProjectEndpointDTO endpointDTO) {
+		Optional<EdgeInfo> edgeInfo = Optional.ofNullable(endpointDTO.getEdgeInfo());
+		if (!edgeInfo.isPresent()) {
+			return Collections.emptyMap();
+		}
+		EdgeInfo edge = edgeInfo.get();
+		Map<String, String> shared = new HashMap<>();
+
+		shared.put("status", endpointDTO.getStatus().toString());
+		shared.put("edge_node_ip", edge.getPublicIp());
+		if (edge instanceof EdgeInfoAws) {
+			EdgeInfoAws edgeInfoAws = (EdgeInfoAws) edge;
+			shared.put("user_own_bicket_name", edgeInfoAws.getUserOwnBucketName());
+			shared.put("shared_bucket_name", edgeInfoAws.getSharedBucketName());
+		} else if (edge instanceof EdgeInfoAzure) {
+			EdgeInfoAzure edgeInfoAzure = (EdgeInfoAzure) edge;
+			shared.put("user_container_name", edgeInfoAzure.getUserContainerName());
+			shared.put("shared_container_name", edgeInfoAzure.getSharedContainerName());
+			shared.put("user_storage_account_name", edgeInfoAzure.getUserStorageAccountName());
+			shared.put("shared_storage_account_name", edgeInfoAzure.getSharedStorageAccountName());
+			shared.put("datalake_name", edgeInfoAzure.getDataLakeName());
+			shared.put("datalake_user_directory_name", edgeInfoAzure.getDataLakeDirectoryName());
+			shared.put("datalake_shared_directory_name", edgeInfoAzure.getDataLakeSharedDirectoryName());
+		} else if (edge instanceof EdgeInfoGcp) {
+			EdgeInfoGcp edgeInfoGcp = (EdgeInfoGcp) edge;
+			shared.put("user_own_bucket_name", edgeInfoGcp.getUserOwnBucketName());
+			shared.put("shared_bucket_name", edgeInfoGcp.getSharedBucketName());
+		}
+
+		return shared;
+	}
+
+	private boolean checkAccess(UserInfo userInfo, String permission) {
+		return UserRoles.checkAccess(userInfo, RoleType.PAGE, permission, userInfo.getRoles());
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureTemplateServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureTemplateServiceImpl.java
new file mode 100644
index 0000000..de4e6e5
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureTemplateServiceImpl.java
@@ -0,0 +1,246 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.ProjectDAO;
+import com.epam.datalab.backendapi.dao.SettingsDAO;
+import com.epam.datalab.backendapi.dao.UserGroupDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.resources.dto.SparkStandaloneConfiguration;
+import com.epam.datalab.backendapi.resources.dto.aws.AwsEmrConfiguration;
+import com.epam.datalab.backendapi.resources.dto.gcp.GcpDataprocConfiguration;
+import com.epam.datalab.backendapi.roles.RoleType;
+import com.epam.datalab.backendapi.roles.UserRoles;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.InfrastructureTemplateService;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.base.computational.FullComputationalTemplate;
+import com.epam.datalab.dto.imagemetadata.ComputationalMetadataDTO;
+import com.epam.datalab.dto.imagemetadata.ComputationalResourceShapeDto;
+import com.epam.datalab.dto.imagemetadata.ExploratoryMetadataDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.cloud.CloudProvider.AZURE;
+import static com.epam.datalab.rest.contracts.DockerAPI.DOCKER_COMPUTATIONAL;
+import static com.epam.datalab.rest.contracts.DockerAPI.DOCKER_EXPLORATORY;
+
+@Slf4j
+public class InfrastructureTemplateServiceImpl implements InfrastructureTemplateService {
+
+    @Inject
+    private SelfServiceApplicationConfiguration configuration;
+    @Inject
+    private SettingsDAO settingsDAO;
+    @Inject
+    private ProjectDAO projectDAO;
+    @Inject
+    private EndpointService endpointService;
+    @Inject
+    private UserGroupDAO userGroupDao;
+
+
+    @Inject
+    @Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
+    private RESTService provisioningService;
+
+    @Override
+    public List<ExploratoryMetadataDTO> getExploratoryTemplates(UserInfo user, String project, String endpoint) {
+
+        log.debug("Loading list of exploratory templates for user {} for project {}", user.getName(), project);
+        try {
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            ExploratoryMetadataDTO[] array =
+                    provisioningService.get(endpointDTO.getUrl() + DOCKER_EXPLORATORY,
+                            user.getAccessToken(),
+                            ExploratoryMetadataDTO[].class);
+
+            final Set<String> roles = userGroupDao.getUserGroups(user.getName());
+            return Arrays.stream(array)
+                    .peek(e -> e.setImage(getSimpleImageName(e.getImage())))
+                    .filter(e -> exploratoryGpuIssuesAzureFilter(e, endpointDTO.getCloudProvider()) &&
+                            UserRoles.checkAccess(user, RoleType.EXPLORATORY, e.getImage(), roles))
+                    .peek(e -> filterShapes(user, e.getExploratoryEnvironmentShapes(), RoleType.EXPLORATORY_SHAPES, roles))
+                    .collect(Collectors.toList());
+
+        } catch (DatalabException e) {
+            log.error("Could not load list of exploratory templates for user: {}", user.getName(), e);
+            throw e;
+        }
+    }
+
+    @Override
+    public List<FullComputationalTemplate> getComputationalTemplates(UserInfo user, String project, String endpoint) {
+
+        log.debug("Loading list of computational templates for user {}", user.getName());
+        try {
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            ComputationalMetadataDTO[] array =
+                    provisioningService.get(endpointDTO.getUrl() + DOCKER_COMPUTATIONAL,
+                            user.getAccessToken(), ComputationalMetadataDTO[]
+                                    .class);
+
+            final Set<String> roles = userGroupDao.getUserGroups(user.getName());
+
+            return Arrays.stream(array)
+                    .peek(e -> e.setImage(getSimpleImageName(e.getImage())))
+                    .peek(e -> filterShapes(user, e.getComputationResourceShapes(), RoleType.COMPUTATIONAL_SHAPES, roles))
+                    .filter(e -> UserRoles.checkAccess(user, RoleType.COMPUTATIONAL, e.getImage(), roles))
+                    .map(comp -> fullComputationalTemplate(comp, endpointDTO.getCloudProvider()))
+                    .collect(Collectors.toList());
+
+        } catch (DatalabException e) {
+            log.error("Could not load list of computational templates for user: {}", user.getName(), e);
+            throw e;
+        }
+    }
+
+    /**
+     * Removes shapes for which user does not have an access
+     *
+     * @param user              user
+     * @param environmentShapes shape types
+     * @param roleType
+     * @param roles
+     */
+    private void filterShapes(UserInfo user, Map<String, List<ComputationalResourceShapeDto>> environmentShapes,
+                              RoleType roleType, Set<String> roles) {
+        environmentShapes.forEach((k, v) -> v.removeIf(compResShapeDto ->
+                !UserRoles.checkAccess(user, roleType, compResShapeDto.getType(), roles))
+        );
+    }
+
+    /**
+     * Temporary filter for creation of exploratory env due to Azure issues
+     */
+    private boolean exploratoryGpuIssuesAzureFilter(ExploratoryMetadataDTO e, CloudProvider cloudProvider) {
+        return (!"redhat".equals(settingsDAO.getConfOsFamily()) || cloudProvider != AZURE) ||
+                !(e.getImage().endsWith("deeplearning") || e.getImage().endsWith("tensor"));
+    }
+
+    /**
+     * Return the image name without suffix version.
+     *
+     * @param imageName the name of image.
+     */
+    private String getSimpleImageName(String imageName) {
+        int separatorIndex = imageName.indexOf(':');
+        return (separatorIndex > 0 ? imageName.substring(0, separatorIndex) : imageName);
+    }
+
+    /**
+     * Wraps metadata with limits
+     *
+     * @param metadataDTO   metadata
+     * @param cloudProvider cloudProvider
+     * @return wrapped object
+     */
+
+    private FullComputationalTemplate fullComputationalTemplate(ComputationalMetadataDTO metadataDTO,
+                                                                CloudProvider cloudProvider) {
+
+        DataEngineType dataEngineType = DataEngineType.fromDockerImageName(metadataDTO.getImage());
+
+        if (dataEngineType == DataEngineType.CLOUD_SERVICE) {
+            return getCloudFullComputationalTemplate(metadataDTO, cloudProvider);
+        } else if (dataEngineType == DataEngineType.SPARK_STANDALONE) {
+            return new SparkFullComputationalTemplate(metadataDTO,
+                    SparkStandaloneConfiguration.builder()
+                            .maxSparkInstanceCount(configuration.getMaxSparkInstanceCount())
+                            .minSparkInstanceCount(configuration.getMinSparkInstanceCount())
+                            .build());
+        } else {
+            throw new IllegalArgumentException("Unknown data engine " + dataEngineType);
+        }
+    }
+
+    protected FullComputationalTemplate getCloudFullComputationalTemplate(ComputationalMetadataDTO metadataDTO,
+                                                                          CloudProvider cloudProvider) {
+        switch (cloudProvider) {
+            case AWS:
+                return new AwsFullComputationalTemplate(metadataDTO,
+                        AwsEmrConfiguration.builder()
+                                .minEmrInstanceCount(configuration.getMinEmrInstanceCount())
+                                .maxEmrInstanceCount(configuration.getMaxEmrInstanceCount())
+                                .maxEmrSpotInstanceBidPct(configuration.getMaxEmrSpotInstanceBidPct())
+                                .minEmrSpotInstanceBidPct(configuration.getMinEmrSpotInstanceBidPct())
+                                .build());
+            case GCP:
+                return new GcpFullComputationalTemplate(metadataDTO,
+                        GcpDataprocConfiguration.builder()
+                                .minInstanceCount(configuration.getMinInstanceCount())
+                                .maxInstanceCount(configuration.getMaxInstanceCount())
+                                .minDataprocPreemptibleInstanceCount(configuration.getMinDataprocPreemptibleCount())
+                                .build());
+            case AZURE:
+                log.error("Dataengine service is not supported currently for {}", AZURE);
+                throw new UnsupportedOperationException("Dataengine service is not supported currently for " + AZURE);
+            default:
+                throw new UnsupportedOperationException("Dataengine service is not supported currently for " + cloudProvider);
+        }
+    }
+
+    private class AwsFullComputationalTemplate extends FullComputationalTemplate {
+        @JsonProperty("limits")
+        private AwsEmrConfiguration awsEmrConfiguration;
+
+        AwsFullComputationalTemplate(ComputationalMetadataDTO metadataDTO,
+                                     AwsEmrConfiguration awsEmrConfiguration) {
+            super(metadataDTO);
+            this.awsEmrConfiguration = awsEmrConfiguration;
+        }
+    }
+
+    private class GcpFullComputationalTemplate extends FullComputationalTemplate {
+        @JsonProperty("limits")
+        private GcpDataprocConfiguration gcpDataprocConfiguration;
+
+        GcpFullComputationalTemplate(ComputationalMetadataDTO metadataDTO,
+                                     GcpDataprocConfiguration gcpDataprocConfiguration) {
+            super(metadataDTO);
+            this.gcpDataprocConfiguration = gcpDataprocConfiguration;
+        }
+    }
+
+    private class SparkFullComputationalTemplate extends FullComputationalTemplate {
+        @JsonProperty("limits")
+        private SparkStandaloneConfiguration sparkStandaloneConfiguration;
+
+        SparkFullComputationalTemplate(ComputationalMetadataDTO metadataDTO,
+                                       SparkStandaloneConfiguration sparkStandaloneConfiguration) {
+            super(metadataDTO);
+            this.sparkStandaloneConfiguration = sparkStandaloneConfiguration;
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/LibraryServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/LibraryServiceImpl.java
new file mode 100644
index 0000000..98fab68
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/LibraryServiceImpl.java
@@ -0,0 +1,311 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Audit;
+import com.epam.datalab.backendapi.annotation.Info;
+import com.epam.datalab.backendapi.annotation.Project;
+import com.epam.datalab.backendapi.annotation.ResourceName;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.dao.BaseDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryLibDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.NotebookTemplate;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.resources.dto.LibInfoRecord;
+import com.epam.datalab.backendapi.resources.dto.LibKey;
+import com.epam.datalab.backendapi.resources.dto.LibraryStatus;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.LibraryService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.LibraryGroups;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.dto.exploratory.LibInstallDTO;
+import com.epam.datalab.dto.exploratory.LibStatus;
+import com.epam.datalab.dto.exploratory.LibraryInstallDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.model.library.Library;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.ComputationalAPI;
+import com.epam.datalab.rest.contracts.ExploratoryAPI;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.bson.Document;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.INSTALL_LIBS;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.COMPUTE;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.NOTEBOOK;
+import static com.epam.datalab.backendapi.domain.NotebookTemplate.DEEP_LEARNING;
+import static com.epam.datalab.backendapi.domain.NotebookTemplate.JUPYTER;
+import static com.epam.datalab.backendapi.domain.NotebookTemplate.RSTUDIO;
+import static com.epam.datalab.backendapi.domain.NotebookTemplate.TENSOR;
+import static com.epam.datalab.backendapi.domain.NotebookTemplate.TENSOR_RSTUDIO;
+import static com.epam.datalab.backendapi.domain.NotebookTemplate.ZEPPELIN;
+import static com.epam.datalab.dto.LibraryGroups.GROUP_JAVA;
+import static com.epam.datalab.dto.LibraryGroups.GROUP_OS_PKG;
+import static com.epam.datalab.dto.LibraryGroups.GROUP_OTHERS;
+import static com.epam.datalab.dto.LibraryGroups.GROUP_PIP2;
+import static com.epam.datalab.dto.LibraryGroups.GROUP_PIP3;
+import static com.epam.datalab.dto.LibraryGroups.GROUP_R_PKG;
+
+
+@Slf4j
+@Singleton
+public class LibraryServiceImpl implements LibraryService {
+    private static final String COMPUTATIONAL_NOT_FOUND_MSG = "Computational with name %s was not found";
+    private static final String LIB_ALREADY_INSTALLED = "Library %s is already installing";
+
+    @Inject
+    private ExploratoryDAO exploratoryDAO;
+
+    @Inject
+    private ExploratoryLibDAO libraryDAO;
+
+    @Inject
+    private RequestBuilder requestBuilder;
+
+    @Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
+    @Inject
+    private RESTService provisioningService;
+
+    @Inject
+    private RequestId requestId;
+
+    @Inject
+    private EndpointService endpointService;
+
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<Document> getLibs(String user, String project, String exploratoryName, String computationalName) {
+        if (StringUtils.isEmpty(computationalName)) {
+            return (List<Document>) libraryDAO.findExploratoryLibraries(user, project, exploratoryName)
+                    .getOrDefault(ExploratoryLibDAO.EXPLORATORY_LIBS, new ArrayList<>());
+        } else {
+            Document document = (Document) libraryDAO.findComputationalLibraries(user, project,
+                    exploratoryName, computationalName)
+                    .getOrDefault(ExploratoryLibDAO.COMPUTATIONAL_LIBS, new Document());
+
+            return (List<Document>) document.getOrDefault(computationalName, new ArrayList<>());
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<LibInfoRecord> getLibInfo(String user, String project, String exploratoryName) {
+        Document document = libraryDAO.findAllLibraries(user, project, exploratoryName);
+
+        Map<LibKey, List<LibraryStatus>> model = new LinkedHashMap<>();
+        if (document.get(ExploratoryLibDAO.EXPLORATORY_LIBS) != null) {
+            List<Document> exploratoryLibs = (List<Document>) document.get(ExploratoryLibDAO.EXPLORATORY_LIBS);
+            exploratoryLibs.forEach(e -> populateModel(exploratoryName, e, model, "notebook"));
+        }
+        if (document.get(ExploratoryLibDAO.COMPUTATIONAL_LIBS) != null) {
+            Document computationalLibs = getLibsOfActiveComputationalResources(document);
+            populateComputational(computationalLibs, model, "cluster");
+        }
+
+        LinkedList<LibInfoRecord> libInfoRecords = new LinkedList<>();
+        for (Map.Entry<LibKey, List<LibraryStatus>> entry : model.entrySet()) {
+            libInfoRecords.addFirst(new LibInfoRecord(entry.getKey(), entry.getValue()));
+        }
+
+        return libInfoRecords;
+    }
+
+    @Audit(action = INSTALL_LIBS, type = COMPUTE)
+    @Override
+    public String installComputationalLibs(@User UserInfo ui, @Project String project, String expName, @ResourceName String compName,
+                                           List<LibInstallDTO> libs, @Info String auditInfo) {
+        final UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(ui.getName(), project, expName, compName);
+        EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
+        final String uuid = provisioningService.post(endpointDTO.getUrl() + ComputationalAPI.COMPUTATIONAL_LIB_INSTALL,
+                ui.getAccessToken(),
+                toComputationalLibraryInstallDto(ui, project, expName, compName, libs, userInstance, endpointDTO),
+                String.class);
+        requestId.put(ui.getName(), uuid);
+        return uuid;
+    }
+
+    @Audit(action = INSTALL_LIBS, type = NOTEBOOK)
+    @Override
+    public String installExploratoryLibs(@User UserInfo ui, @Project String project, @ResourceName String expName, List<LibInstallDTO> libs, @Info String auditInfo) {
+        final UserInstanceDTO userInstance = exploratoryDAO.fetchRunningExploratoryFields(ui.getName(), project, expName);
+        EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
+        final String uuid = provisioningService.post(endpointDTO.getUrl() + ExploratoryAPI.EXPLORATORY_LIB_INSTALL,
+                ui.getAccessToken(), toExploratoryLibraryInstallDto(ui, project, expName, libs, userInstance, endpointDTO),
+                String.class);
+        requestId.put(ui.getName(), uuid);
+        return uuid;
+    }
+
+    @Override
+    public List<String> getExploratoryLibGroups(UserInfo userInfo, String projectName, String exploratoryName) {
+        UserInstanceDTO userInstanceDTO = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), projectName, exploratoryName);
+        final String templateName = userInstanceDTO.getTemplateName();
+        List<LibraryGroups> groups = new ArrayList<>(Arrays.asList(GROUP_PIP2, GROUP_PIP3, GROUP_OTHERS, GROUP_OS_PKG));
+
+        if (isTemplateGroup(templateName, Stream.of(JUPYTER, ZEPPELIN))) {
+            groups.addAll(Arrays.asList(GROUP_R_PKG, GROUP_JAVA));
+        }
+        if (isTemplateGroup(templateName, Stream.of(DEEP_LEARNING, TENSOR))) {
+            groups.add(GROUP_JAVA);
+        }
+        if (isTemplateGroup(templateName, Stream.of(RSTUDIO, TENSOR_RSTUDIO))) {
+            groups.add(GROUP_R_PKG);
+        }
+
+        return groups
+                .stream()
+                .map(LibraryGroups::toString)
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public List<String> getComputeLibGroups() {
+        return Stream.of(GROUP_PIP3, GROUP_OTHERS, GROUP_R_PKG, GROUP_OS_PKG, GROUP_JAVA)
+                .map(LibraryGroups::toString)
+                .collect(Collectors.toList());
+    }
+
+    private boolean isTemplateGroup(String templateName, Stream<NotebookTemplate> templateStream) {
+        return templateStream
+                .map(NotebookTemplate::getName)
+                .anyMatch(name -> name.equals(templateName));
+    }
+
+    private LibraryInstallDTO toExploratoryLibraryInstallDto(UserInfo userInfo, String project, String exploratoryName,
+                                                             List<LibInstallDTO> libs, UserInstanceDTO userInstance, EndpointDTO endpointDTO) {
+        final List<LibInstallDTO> libsToInstall = libs.stream()
+                .map(lib -> toLibInstallDto(lib, libraryDAO.getLibrary(userInfo.getName(), project, exploratoryName,
+                        lib.getGroup(), lib.getName())))
+                .peek(l -> libraryDAO.addLibrary(userInfo.getName(), project, exploratoryName, l, l.isOverride()))
+                .collect(Collectors.toList());
+        return requestBuilder.newLibInstall(userInfo, userInstance, endpointDTO, libsToInstall);
+    }
+
+    private LibraryInstallDTO toComputationalLibraryInstallDto(UserInfo userInfo, String project, String expName,
+                                                               String compName, List<LibInstallDTO> libs,
+                                                               UserInstanceDTO userInstance, EndpointDTO endpointDTO) {
+
+        final UserComputationalResource computationalResource = getComputationalResource(compName, userInstance);
+        final List<LibInstallDTO> libsToInstall = libs.stream()
+                .map(lib -> toLibInstallDto(lib, libraryDAO.getLibrary(userInfo.getName(), project,
+                        expName, compName, lib.getGroup(), lib.getName())))
+                .peek(l -> libraryDAO.addLibrary(userInfo.getName(), project, expName, compName,
+                        l, l.isOverride()))
+                .collect(Collectors.toList());
+        return requestBuilder.newLibInstall(userInfo, userInstance, computationalResource, libsToInstall, endpointDTO);
+    }
+
+    private UserComputationalResource getComputationalResource(String computationalName,
+                                                               UserInstanceDTO userInstance) {
+        return userInstance.getResources()
+                .stream()
+                .filter(computational -> computational.getComputationalName().equals(computationalName))
+                .findAny()
+                .orElseThrow(() -> new DatalabException(String.format(COMPUTATIONAL_NOT_FOUND_MSG, computationalName)));
+    }
+
+    private LibInstallDTO toLibInstallDto(LibInstallDTO lib, Library existingLibrary) {
+        final LibInstallDTO l = new LibInstallDTO(lib.getGroup(), lib.getName(), lib.getVersion());
+        l.setStatus(LibStatus.INSTALLING.toString());
+        l.setOverride(shouldOverride(existingLibrary));
+        return l;
+    }
+
+    private boolean shouldOverride(Library library) {
+        if (Objects.nonNull(library) && library.getStatus() == LibStatus.INSTALLING) {
+            throw new DatalabException(String.format(LIB_ALREADY_INSTALLED, library.getName()));
+        } else {
+            return Objects.nonNull(library);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private Document getLibsOfActiveComputationalResources(Document document) {
+        Document computationalLibs = (Document) document.get(ExploratoryLibDAO.COMPUTATIONAL_LIBS);
+
+        if (document.get(ExploratoryDAO.COMPUTATIONAL_RESOURCES) != null) {
+            List<Document> computationalResources = (List<Document>) document.get(ExploratoryDAO
+                    .COMPUTATIONAL_RESOURCES);
+
+            Set<String> terminated = computationalResources.stream()
+                    .filter(doc -> doc.getString(BaseDAO.STATUS).equalsIgnoreCase(UserInstanceStatus.TERMINATED
+                            .toString()))
+                    .map(doc -> doc.getString("computational_name")).collect(Collectors.toSet());
+
+            terminated.forEach(computationalLibs::remove);
+        }
+
+        return computationalLibs;
+    }
+
+
+    private void populateModel(String exploratoryName, Document document, Map<LibKey, List<LibraryStatus>> model,
+                               String resourceType) {
+        String name = document.getString(ExploratoryLibDAO.LIB_NAME);
+        String version = document.getString(ExploratoryLibDAO.LIB_VERSION);
+        String group = document.getString(ExploratoryLibDAO.LIB_GROUP);
+        String status = document.getString(ExploratoryLibDAO.STATUS);
+        List<String> availableVersions = (List<String>) document.get(ExploratoryLibDAO.LIB_AVAILABLE_VERSION);
+        List<String> addedPackages = (List<String>) document.get(ExploratoryLibDAO.LIB_ADDED_PACKAGES);
+        String error = document.getString(ExploratoryLibDAO.ERROR_MESSAGE);
+
+        LibKey libKey = new LibKey(name, version, group);
+        List<LibraryStatus> statuses = model.getOrDefault(libKey, new ArrayList<>());
+
+        if (statuses.isEmpty()) {
+            model.put(libKey, statuses);
+        }
+
+        statuses.add(new LibraryStatus(exploratoryName, resourceType, status, error, availableVersions, addedPackages));
+    }
+
+    @SuppressWarnings("unchecked")
+    private void populateComputational(Document computationalLibs, Map<LibKey, List<LibraryStatus>> model, String
+            resourceType) {
+        for (Map.Entry<String, Object> entry : computationalLibs.entrySet()) {
+            if (entry.getValue() != null) {
+                List<Document> docs = (List<Document>) entry.getValue();
+                docs.forEach(e -> populateModel(entry.getKey(), e, model, resourceType));
+            }
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/MavenCentralLibraryService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/MavenCentralLibraryService.java
new file mode 100644
index 0000000..26569cc
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/MavenCentralLibraryService.java
@@ -0,0 +1,88 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.domain.MavenSearchArtifactResponse;
+import com.epam.datalab.backendapi.resources.dto.LibraryDTO;
+import com.epam.datalab.backendapi.service.ExternalLibraryService;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.inject.Inject;
+import java.net.URI;
+
+import static java.lang.String.join;
+
+@Singleton
+@Slf4j
+public class MavenCentralLibraryService implements ExternalLibraryService {
+
+    private static final String QUOTE_ENCODED = "%22";
+    private static final String SEARCH_API_QUERY_FORMAT = "/solrsearch/select?q=%s&rows=20&wt=json&core=gav&p=jar";
+    private static final String LIB_NOT_FOUND_MSG = "No matches found";
+    private final RESTService restClient;
+
+    @Inject
+    public MavenCentralLibraryService(@Named(ServiceConsts.MAVEN_SEARCH_API) RESTService restClient) {
+        this.restClient = restClient;
+    }
+
+    @Override
+    public LibraryDTO getLibrary(String groupId, String artifactId, String version) {
+        return getMavenLibrary(groupId, artifactId, version);
+
+    }
+
+    private LibraryDTO getMavenLibrary(String groupId, String artifactId, String version) {
+        final String query = and(artifactQuery(artifactId), groupQuery(groupId), versionQuery(version), jarOrBundlePackage());
+        return restClient.get(URI.create(String.format(SEARCH_API_QUERY_FORMAT, query)),
+                MavenSearchArtifactResponse.class)
+                .getArtifacts()
+                .stream()
+                .findFirst()
+                .map(artifact -> new LibraryDTO(join(":", groupId, artifactId), version))
+                .orElseThrow(() -> new ResourceNotFoundException(LIB_NOT_FOUND_MSG));
+    }
+
+    private String groupQuery(String groupId) {
+        return "g:" + QUOTE_ENCODED + groupId + QUOTE_ENCODED;
+    }
+
+    private String artifactQuery(String artifactId) {
+        return "a:" + QUOTE_ENCODED + artifactId + QUOTE_ENCODED;
+    }
+
+    private String versionQuery(String version) {
+        return "v:" + QUOTE_ENCODED + version + QUOTE_ENCODED;
+    }
+
+    private String jarOrBundlePackage() {
+        return "(p:" + QUOTE_ENCODED + "jar" + QUOTE_ENCODED + "%20OR%20p:" + QUOTE_ENCODED + "bundle" + QUOTE_ENCODED + ")";
+    }
+
+    private String and(String... strings) {
+        return join("+AND+", strings);
+    }
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java
new file mode 100644
index 0000000..54d0495
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java
@@ -0,0 +1,386 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Audit;
+import com.epam.datalab.backendapi.annotation.BudgetLimited;
+import com.epam.datalab.backendapi.annotation.Info;
+import com.epam.datalab.backendapi.annotation.Project;
+import com.epam.datalab.backendapi.annotation.ProjectAdmin;
+import com.epam.datalab.backendapi.annotation.ResourceName;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.ProjectDAO;
+import com.epam.datalab.backendapi.dao.UserGroupDAO;
+import com.epam.datalab.backendapi.domain.BudgetDTO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectEndpointDTO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.domain.UpdateProjectBudgetDTO;
+import com.epam.datalab.backendapi.domain.UpdateProjectDTO;
+import com.epam.datalab.backendapi.roles.UserRoles;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.exceptions.ResourceConflictException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.CREATE;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.START;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.STOP;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.TERMINATE;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.UPDATE;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.EDGE_NODE;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.PROJECT;
+import static java.util.stream.Collectors.toSet;
+import static java.util.stream.Stream.concat;
+
+@Slf4j
+public class ProjectServiceImpl implements ProjectService {
+
+    private static final String CREATE_PRJ_API = "infrastructure/project/create";
+    private static final String TERMINATE_PRJ_API = "infrastructure/project/terminate";
+    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 TOTAL_BUDGET_PERIOD = "Total";
+    private static final String MONTHLY_BUDGET_PERIOD = "Monthly";
+
+    private static final String AUDIT_ADD_ENDPOINT = "Add endpoint(s): %s\n";
+    private static final String AUDIT_ADD_GROUP = "Add group(s): %s\n";
+    private static final String AUDIT_REMOVE_GROUP = "Remove group(s): %s\n";
+    private static final String AUDIT_UPDATE_BUDGET = "Update quota: %d->%d\nUpdate period: %s->%s";
+    private static final String AUDIT_ADD_EDGE_NODE = "Create edge node for endpoint %s, requested in project %s";
+
+    private final ProjectDAO projectDAO;
+    private final ExploratoryService exploratoryService;
+    private final UserGroupDAO userGroupDao;
+    private final RESTService provisioningService;
+    private final RequestId requestId;
+    private final RequestBuilder requestBuilder;
+    private final EndpointService endpointService;
+    private final ExploratoryDAO exploratoryDAO;
+    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, SelfServiceApplicationConfiguration configuration) {
+        this.projectDAO = projectDAO;
+        this.exploratoryService = exploratoryService;
+        this.userGroupDao = userGroupDao;
+        this.provisioningService = provisioningService;
+        this.requestId = requestId;
+        this.requestBuilder = requestBuilder;
+        this.endpointService = endpointService;
+        this.exploratoryDAO = exploratoryDAO;
+        this.configuration = configuration;
+    }
+
+    @Override
+    public List<ProjectDTO> getProjects() {
+        return projectDAO.getProjects();
+    }
+
+    @Override
+    public List<ProjectDTO> getProjects(UserInfo user) {
+        return projectDAO.getProjects()
+                .stream()
+                .filter(project -> UserRoles.isProjectAdmin(user, project.getGroups()) || UserRoles.isAdmin(user))
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public List<ProjectDTO> getUserProjects(UserInfo userInfo, boolean active) {
+        return projectDAO.getUserProjects(userInfo, active);
+    }
+
+    @Override
+    public List<ProjectDTO> getProjectsByEndpoint(String endpointName) {
+        return projectDAO.getProjectsByEndpoint(endpointName);
+    }
+
+    @BudgetLimited
+    @Override
+    public void create(UserInfo user, ProjectDTO projectDTO, String resourceName) {
+        if (!projectDAO.get(projectDTO.getName()).isPresent()) {
+            projectDAO.create(projectDTO);
+            createProjectOnCloud(user, projectDTO);
+        } else {
+            throw new ResourceConflictException("Project with passed name already exist in system");
+        }
+    }
+
+    @Override
+    public ProjectDTO get(String name) {
+        return projectDAO.get(name)
+                .orElseThrow(projectNotFound());
+    }
+
+    @Audit(action = TERMINATE, type = EDGE_NODE)
+    @Override
+    public void terminateEndpoint(@User UserInfo userInfo, @ResourceName String endpoint, @Project String name) {
+        projectActionOnCloud(userInfo, name, TERMINATE_PRJ_API, endpoint);
+        projectDAO.updateEdgeStatus(name, endpoint, UserInstanceStatus.TERMINATING);
+        exploratoryService.updateProjectExploratoryStatuses(userInfo, name, endpoint, UserInstanceStatus.TERMINATING);
+    }
+
+    @ProjectAdmin
+    @Override
+    public void terminateEndpoint(@User UserInfo userInfo, List<String> endpoints, @Project String name) {
+        List<ProjectEndpointDTO> endpointDTOs = getProjectEndpointDTOS(endpoints, name);
+        checkProjectRelatedResourcesInProgress(name, endpointDTOs, TERMINATE_ACTION);
+        endpoints.forEach(endpoint -> terminateEndpoint(userInfo, endpoint, name));
+    }
+
+    @BudgetLimited
+    @Audit(action = START, type = EDGE_NODE)
+    @Override
+    public void start(@User UserInfo userInfo, @ResourceName String endpoint, @Project String name) {
+        projectActionOnCloud(userInfo, name, START_PRJ_API, endpoint);
+        projectDAO.updateEdgeStatus(name, endpoint, UserInstanceStatus.STARTING);
+    }
+
+    @ProjectAdmin
+    @Override
+    public void start(@User UserInfo userInfo, List<String> endpoints, @Project String name) {
+        endpoints.forEach(endpoint -> start(userInfo, endpoint, name));
+    }
+
+    @Audit(action = STOP, type = EDGE_NODE)
+    @Override
+    public void stop(@User UserInfo userInfo, @ResourceName String endpoint, @Project String name, @Info String auditInfo) {
+        projectActionOnCloud(userInfo, name, STOP_PRJ_API, endpoint);
+        projectDAO.updateEdgeStatus(name, endpoint, UserInstanceStatus.STOPPING);
+    }
+
+    @ProjectAdmin
+    @Override
+    public void stopWithResources(@User UserInfo userInfo, List<String> endpoints, @ResourceName @Project String projectName) {
+        List<ProjectEndpointDTO> endpointDTOs = getProjectEndpointDTOS(endpoints, projectName);
+        checkProjectRelatedResourcesInProgress(projectName, endpointDTOs, STOP_ACTION);
+
+        endpointDTOs
+                .stream()
+                .filter(e -> !Arrays.asList(UserInstanceStatus.TERMINATED, UserInstanceStatus.TERMINATING, UserInstanceStatus.STOPPED,
+                        UserInstanceStatus.FAILED).contains(e.getStatus()))
+                .forEach(e -> stop(userInfo, e.getName(), projectName, null));
+
+        exploratoryDAO.fetchRunningExploratoryFieldsForProject(projectName,
+                endpointDTOs
+                        .stream()
+                        .map(ProjectEndpointDTO::getName)
+                        .collect(Collectors.toList()))
+                .forEach(e -> exploratoryService.stop(userInfo, e.getUser(), projectName, e.getExploratoryName(), null));
+    }
+
+    @ProjectAdmin
+    @Override
+    public void update(@User UserInfo userInfo, UpdateProjectDTO projectDTO, @Project String projectName) {
+        final ProjectDTO project = projectDAO.get(projectDTO.getName()).orElseThrow(projectNotFound());
+        final Set<String> endpoints = project.getEndpoints()
+                .stream()
+                .map(ProjectEndpointDTO::getName)
+                .collect(toSet());
+        final Set<String> newEndpoints = new HashSet<>(projectDTO.getEndpoints());
+        newEndpoints.removeAll(endpoints);
+        final String projectUpdateAudit = updateProjectAudit(projectDTO, project, newEndpoints);
+        updateProject(userInfo, projectName, projectDTO, project, newEndpoints, projectUpdateAudit);
+    }
+
+    @Audit(action = UPDATE, type = PROJECT)
+    public void updateProject(@User UserInfo userInfo, @Project @ResourceName String projectName, UpdateProjectDTO projectDTO, ProjectDTO project, Set<String> newEndpoints,
+                              @Info String projectAudit) {
+        final List<ProjectEndpointDTO> endpointsToBeCreated = newEndpoints
+                .stream()
+                .map(e -> new ProjectEndpointDTO(e, UserInstanceStatus.CREATING, null))
+                .collect(Collectors.toList());
+        project.getEndpoints().addAll(endpointsToBeCreated);
+        projectDAO.update(new ProjectDTO(project.getName(), projectDTO.getGroups(), project.getKey(),
+                project.getTag(), project.getBudget(), project.getEndpoints(), projectDTO.isSharedImageEnabled()));
+        endpointsToBeCreated.forEach(e -> createEndpoint(userInfo, projectName, project, e.getName(), String.format(AUDIT_ADD_EDGE_NODE, e.getName(), project.getName())));
+    }
+
+    @Override
+    public void updateBudget(UserInfo userInfo, List<UpdateProjectBudgetDTO> dtos) {
+        final List<ProjectDTO> projects = dtos
+                .stream()
+                .map(this::getUpdateProjectDTO)
+                .collect(Collectors.toList());
+
+        projects.forEach(p -> updateBudget(userInfo, p.getName(), p.getBudget(), getUpdateBudgetAudit(p)));
+    }
+
+    @Audit(action = UPDATE, type = PROJECT)
+    public void updateBudget(@User UserInfo userInfo, @Project @ResourceName String name, BudgetDTO budget, @Info String updateBudgetAudit) {
+        projectDAO.updateBudget(name, budget.getValue(), budget.isMonthlyBudget());
+    }
+
+    @Override
+    public boolean isAnyProjectAssigned(UserInfo userInfo) {
+        final Set<String> userGroups = concat(userInfo.getRoles().stream(),
+                userGroupDao.getUserGroups(userInfo.getName()).stream())
+                .collect(toSet());
+        return projectDAO.isAnyProjectAssigned(userGroups);
+    }
+
+    @Override
+    public boolean checkExploratoriesAndComputationalProgress(String projectName, List<String> endpoints) {
+        return exploratoryDAO.fetchProjectEndpointExploratoriesWhereStatusIn(projectName, endpoints, Arrays.asList(
+                UserInstanceStatus.CREATING, UserInstanceStatus.STARTING, UserInstanceStatus.CREATING_IMAGE,
+                UserInstanceStatus.CONFIGURING, UserInstanceStatus.RECONFIGURING, UserInstanceStatus.STOPPING,
+                UserInstanceStatus.TERMINATING),
+                UserInstanceStatus.CREATING, UserInstanceStatus.CONFIGURING, UserInstanceStatus.STARTING,
+                UserInstanceStatus.RECONFIGURING, UserInstanceStatus.CREATING_IMAGE, UserInstanceStatus.STOPPING,
+                UserInstanceStatus.TERMINATING).isEmpty();
+    }
+
+    private void createProjectOnCloud(UserInfo user, ProjectDTO project) {
+        try {
+            project.getEndpoints().forEach(e -> createEndpoint(user, project.getName(), project, e.getName(), String.format(AUDIT_ADD_EDGE_NODE, e.getName(), project.getName())));
+        } catch (Exception e) {
+            log.error("Can not create project due to: {}", e.getMessage(), e);
+            projectDAO.updateStatus(project.getName(), ProjectDTO.Status.FAILED);
+        }
+    }
+
+    @Audit(action = CREATE, type = EDGE_NODE)
+    public void createEndpoint(@User UserInfo user, @Project String projectName, ProjectDTO projectDTO, @ResourceName String endpointName, @Info String auditInfo) {
+        EndpointDTO endpointDTO = endpointService.get(endpointName);
+        String uuid = provisioningService.post(endpointDTO.getUrl() + CREATE_PRJ_API, user.getAccessToken(),
+                requestBuilder.newProjectCreate(user, projectDTO, endpointDTO), String.class);
+        requestId.put(user.getName(), uuid);
+    }
+
+    private void projectActionOnCloud(UserInfo user, String projectName, String provisioningApiUri, String endpoint) {
+        try {
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            String uuid = provisioningService.post(endpointDTO.getUrl() + provisioningApiUri, user.getAccessToken(),
+                    requestBuilder.newProjectAction(user, projectName, endpointDTO), String.class);
+            requestId.put(user.getName(), uuid);
+        } catch (Exception e) {
+            log.error("Can not terminate project due to: {}", e.getMessage(), e);
+            projectDAO.updateStatus(projectName, ProjectDTO.Status.FAILED);
+        }
+    }
+
+    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()));
+
+        List<String> endpointNames = endpoints
+                .stream()
+                .map(ProjectEndpointDTO::getName)
+                .collect(Collectors.toList());
+        if (edgeProgress || !checkExploratoriesAndComputationalProgress(projectName, endpointNames)) {
+            throw new ResourceConflictException((String.format("Can not %s environment because one of project " +
+                    "resource is in processing stage", action)));
+        }
+    }
+
+    private String updateProjectAudit(UpdateProjectDTO projectDTO, ProjectDTO project, Set<String> newEndpoints) {
+        if (!configuration.isAuditEnabled()) {
+            return null;
+        }
+        StringBuilder audit = new StringBuilder();
+        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.append(String.format(AUDIT_ADD_ENDPOINT, String.join(", ", newEndpoints)));
+        }
+        if (!newGroups.isEmpty()) {
+            audit.append(String.format(AUDIT_ADD_GROUP, String.join(", ", newGroups)));
+        }
+        if (!removedGroups.isEmpty()) {
+            audit.append(String.format(AUDIT_REMOVE_GROUP, String.join(", ", removedGroups)));
+        }
+        return audit.toString();
+    }
+
+    private String getUpdateBudgetAudit(ProjectDTO p) {
+        if (!configuration.isAuditEnabled()) {
+            return null;
+        }
+        ProjectDTO projectDTO = get(p.getName());
+        Integer value = Optional.ofNullable(projectDTO.getBudget())
+                .map(BudgetDTO::getValue)
+                .orElse(null);
+        Boolean monthlyBudget = Optional.ofNullable(projectDTO.getBudget())
+                .map(BudgetDTO::isMonthlyBudget)
+                .orElse(null);
+        return String.format(AUDIT_UPDATE_BUDGET, value, p.getBudget().getValue(),
+                representBudgetType(monthlyBudget), representBudgetType(p.getBudget().isMonthlyBudget()));
+    }
+
+    private String representBudgetType(Boolean isMonthlyPeriod) {
+        return (isMonthlyPeriod) ? MONTHLY_BUDGET_PERIOD : TOTAL_BUDGET_PERIOD;
+    }
+
+    private List<ProjectEndpointDTO> getProjectEndpointDTOS(List<String> endpoints, @Project String name) {
+        return get(name)
+                .getEndpoints()
+                .stream()
+                .filter(projectEndpointDTO -> endpoints.contains(projectEndpointDTO.getName()))
+                .collect(Collectors.toList());
+    }
+
+    private ProjectDTO getUpdateProjectDTO(UpdateProjectBudgetDTO dto) {
+        BudgetDTO budgetDTO = BudgetDTO.builder()
+                .value(dto.getBudget())
+                .monthlyBudget(dto.isMonthlyBudget())
+                .build();
+        return ProjectDTO.builder()
+                .name(dto.getProject())
+                .budget(budgetDTO)
+                .build();
+    }
+
+    private Supplier<ResourceNotFoundException> projectNotFound() {
+        return () -> new ResourceNotFoundException("Project with passed name not found");
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ReuploadKeyServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ReuploadKeyServiceImpl.java
new file mode 100644
index 0000000..093ac7f
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ReuploadKeyServiceImpl.java
@@ -0,0 +1,96 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.dao.ComputationalDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.ReuploadKeyService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyStatus;
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyStatusDTO;
+import com.epam.datalab.model.ResourceData;
+import com.epam.datalab.model.ResourceType;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+
+import static com.epam.datalab.constants.ServiceConsts.PROVISIONING_SERVICE_NAME;
+import static com.epam.datalab.dto.UserInstanceStatus.RUNNING;
+
+@Singleton
+@Slf4j
+public class ReuploadKeyServiceImpl implements ReuploadKeyService {
+
+    @Inject
+    @Named(PROVISIONING_SERVICE_NAME)
+    private RESTService provisioningService;
+    @Inject
+    private RequestBuilder requestBuilder;
+    @Inject
+    private RequestId requestId;
+    @Inject
+    private ExploratoryService exploratoryService;
+    @Inject
+    private ComputationalDAO computationalDAO;
+    @Inject
+    private ExploratoryDAO exploratoryDAO;
+
+    private static final String REUPLOAD_KEY_UPDATE_MSG = "Reuploading key process is successfully finished. " +
+            "Updating 'reupload_key_required' flag to 'false' for {}.";
+    private static final String REUPLOAD_KEY_ERROR_MSG = "Reuploading key process is failed for {}. The next attempt" +
+            "starts after resource restarting.";
+
+    @Override
+    public void updateResourceData(ReuploadKeyStatusDTO dto) {
+        String user = dto.getUser();
+        ResourceData resource = dto.getReuploadKeyCallbackDTO().getResource();
+        log.debug("Updating resource {} to status RUNNING...", resource.toString());
+        updateResourceStatus(user, null, resource, RUNNING);
+        if (dto.getReuploadKeyStatus() == ReuploadKeyStatus.COMPLETED) {
+            log.debug(REUPLOAD_KEY_UPDATE_MSG, resource.toString());
+            updateResourceReuploadKeyFlag(user, null, resource, false);
+        } else {
+            log.error(REUPLOAD_KEY_ERROR_MSG, resource.toString());
+        }
+    }
+
+    private void updateResourceStatus(String user, String project, ResourceData resourceData, UserInstanceStatus newStatus) {
+        if (resourceData.getResourceType() == ResourceType.EXPLORATORY) {
+            exploratoryDAO.updateStatusForExploratory(user, project, resourceData.getExploratoryName(), newStatus);
+        } else if (resourceData.getResourceType() == ResourceType.COMPUTATIONAL) {
+            computationalDAO.updateStatusForComputationalResource(user, project,
+                    resourceData.getExploratoryName(), resourceData.getComputationalName(), newStatus);
+        }
+    }
+
+    private void updateResourceReuploadKeyFlag(String user, String project, ResourceData resourceData, boolean reuploadKeyRequired) {
+        if (resourceData.getResourceType() == ResourceType.EXPLORATORY) {
+            exploratoryDAO.updateReuploadKeyForExploratory(user, project, resourceData.getExploratoryName(), reuploadKeyRequired);
+        } else if (resourceData.getResourceType() == ResourceType.COMPUTATIONAL) {
+            computationalDAO.updateReuploadKeyFlagForComputationalResource(user, project,
+                    resourceData.getExploratoryName(), resourceData.getComputationalName(), reuploadKeyRequired);
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/SchedulerJobServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/SchedulerJobServiceImpl.java
new file mode 100644
index 0000000..546a044
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/SchedulerJobServiceImpl.java
@@ -0,0 +1,514 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Audit;
+import com.epam.datalab.backendapi.annotation.Project;
+import com.epam.datalab.backendapi.annotation.ResourceName;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.dao.ComputationalDAO;
+import com.epam.datalab.backendapi.dao.EnvDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.SchedulerJobDAO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.ComputationalService;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.SchedulerJobService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.exceptions.ResourceInappropriateStateException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.model.scheduler.SchedulerJobData;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoUnit;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.SET_UP_SCHEDULER;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.COMPUTE;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.NOTEBOOK;
+import static com.epam.datalab.constants.ServiceConsts.PROVISIONING_SERVICE_NAME;
+import static com.epam.datalab.dto.UserInstanceStatus.CONFIGURING;
+import static com.epam.datalab.dto.UserInstanceStatus.CREATING;
+import static com.epam.datalab.dto.UserInstanceStatus.RUNNING;
+import static com.epam.datalab.dto.UserInstanceStatus.STARTING;
+import static com.epam.datalab.dto.UserInstanceStatus.STOPPED;
+import static com.epam.datalab.dto.UserInstanceStatus.STOPPING;
+import static com.epam.datalab.dto.UserInstanceStatus.TERMINATING;
+import static com.epam.datalab.dto.base.DataEngineType.getDockerImageName;
+import static java.time.ZoneId.systemDefault;
+import static java.util.Collections.singletonList;
+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 AUDIT_MESSAGE = "Scheduled action, requested for notebook %s";
+    private static final long ALLOWED_INACTIVITY_MINUTES = 1L;
+
+    @Inject
+    private SchedulerJobDAO schedulerJobDAO;
+
+    @Inject
+    private ExploratoryDAO exploratoryDAO;
+
+    @Inject
+    private ComputationalDAO computationalDAO;
+
+    @Inject
+    private ExploratoryService exploratoryService;
+
+    @Inject
+    private ComputationalService computationalService;
+
+    @Inject
+    private SecurityService securityService;
+
+    @Inject
+    private EnvDAO envDAO;
+
+    @Inject
+    private RequestId requestId;
+
+    @Inject
+    @Named(PROVISIONING_SERVICE_NAME)
+    private RESTService provisioningService;
+
+    @Override
+    public SchedulerJobDTO fetchSchedulerJobForUserAndExploratory(String user, String project, String exploratoryName) {
+        return schedulerJobDAO.fetchSingleSchedulerJobByUserAndExploratory(user, project, exploratoryName)
+                .orElseThrow(() -> new ResourceNotFoundException(String.format(SCHEDULER_NOT_FOUND_MSG, user,
+                        exploratoryName)));
+    }
+
+    @Override
+    public SchedulerJobDTO fetchSchedulerJobForComputationalResource(String user, String project, String exploratoryName,
+                                                                     String computationalName) {
+        return schedulerJobDAO.fetchSingleSchedulerJobForCluster(user, project, exploratoryName, computationalName)
+                .orElseThrow(() -> new ResourceNotFoundException(String.format(SCHEDULER_NOT_FOUND_MSG, user,
+                        exploratoryName) + " with computational resource " + computationalName));
+    }
+
+    @Audit(action = SET_UP_SCHEDULER, type = NOTEBOOK)
+    @Override
+    public void updateExploratorySchedulerData(@User UserInfo user, @Project String project, @ResourceName String exploratoryName, SchedulerJobDTO dto) {
+        validateExploratoryStatus(user.getName(), project, exploratoryName);
+        populateDefaultSchedulerValues(dto);
+        log.debug("Updating exploratory {} for user {} with new scheduler job data: {}...", exploratoryName, user,
+                dto);
+        exploratoryDAO.updateSchedulerDataForUserAndExploratory(user.getName(), project, exploratoryName, dto);
+
+        if (!dto.inactivityScheduler() && dto.isSyncStartRequired()) {
+            shareSchedulerJobDataToSparkClusters(user.getName(), project, exploratoryName, dto);
+        } else if (!dto.inactivityScheduler()) {
+            computationalDAO.updateSchedulerSyncFlag(user.getName(), project, exploratoryName, dto.isSyncStartRequired());
+        }
+    }
+
+    @Audit(action = SET_UP_SCHEDULER, type = COMPUTE)
+    @Override
+    public void updateComputationalSchedulerData(@User UserInfo user, @Project String project, String exploratoryName, @ResourceName String computationalName, SchedulerJobDTO dto) {
+        validateExploratoryStatus(user.getName(), project, exploratoryName);
+        validateComputationalStatus(user.getName(), project, exploratoryName, computationalName);
+        populateDefaultSchedulerValues(dto);
+        log.debug("Updating computational resource {} affiliated with exploratory {} for user {} with new scheduler " +
+                "job data {}...", computationalName, exploratoryName, user, dto);
+        computationalDAO.updateSchedulerDataForComputationalResource(user.getName(), project, exploratoryName, computationalName, dto);
+    }
+
+    @Override
+    public void stopComputationalByScheduler() {
+        getComputationalSchedulersForStopping(OffsetDateTime.now(), true)
+                .forEach(this::stopComputational);
+    }
+
+    @Override
+    public void stopExploratoryByScheduler() {
+        getExploratorySchedulersForStopping(OffsetDateTime.now(), true)
+                .forEach(this::stopExploratory);
+    }
+
+    @Override
+    public void startExploratoryByScheduler() {
+        getExploratorySchedulersForStarting(OffsetDateTime.now())
+                .forEach(this::startExploratory);
+    }
+
+    @Override
+    public void startComputationalByScheduler() {
+        getComputationalSchedulersForStarting(OffsetDateTime.now())
+                .forEach(job -> startSpark(job.getUser(), job.getExploratoryName(), job.getComputationalName(),
+                        job.getProject()));
+    }
+
+    @Override
+    public void terminateExploratoryByScheduler() {
+        getExploratorySchedulersForTerminating(OffsetDateTime.now())
+                .forEach(this::terminateExploratory);
+
+    }
+
+    @Override
+    public void terminateComputationalByScheduler() {
+        getComputationalSchedulersForTerminating(OffsetDateTime.now()).forEach(this::terminateComputational);
+
+    }
+
+    @Override
+    public void removeScheduler(String user, String exploratoryName) {
+        schedulerJobDAO.removeScheduler(user, exploratoryName);
+    }
+
+    @Override
+    public void removeScheduler(String user, String exploratoryName, String computationalName) {
+        schedulerJobDAO.removeScheduler(user, exploratoryName, computationalName);
+    }
+
+    @Override
+    public List<SchedulerJobData> getActiveSchedulers(String user, long minutesOffset) {
+        final OffsetDateTime desiredDateTime = OffsetDateTime.now().plusMinutes(minutesOffset);
+        final Predicate<SchedulerJobData> userPredicate = s -> user.equals(s.getUser());
+        final Stream<SchedulerJobData> computationalSchedulersStream =
+                getComputationalSchedulersForStopping(desiredDateTime)
+                        .stream()
+                        .filter(userPredicate);
+        final Stream<SchedulerJobData> exploratorySchedulersStream =
+                getExploratorySchedulersForStopping(desiredDateTime)
+                        .stream()
+                        .filter(userPredicate);
+        return Stream.concat(computationalSchedulersStream, exploratorySchedulersStream)
+                .collect(Collectors.toList());
+    }
+
+    private void stopComputational(SchedulerJobData job) {
+        final String project = job.getProject();
+        final String expName = job.getExploratoryName();
+        final String compName = job.getComputationalName();
+        final String user = job.getUser();
+        log.debug("Stopping exploratory {} computational {} for user {} by scheduler", expName, compName, user);
+        computationalService.stopSparkCluster(securityService.getServiceAccountInfo(user), user, project, expName, compName, String.format(AUDIT_MESSAGE, expName));
+    }
+
+    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, user, job.getProject(), expName, compName, String.format(AUDIT_MESSAGE, expName));
+    }
+
+    private void stopExploratory(SchedulerJobData job) {
+        final String expName = job.getExploratoryName();
+        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), user, project, expName, String.format(AUDIT_MESSAGE, expName));
+    }
+
+    private List<SchedulerJobData> getExploratorySchedulersForTerminating(OffsetDateTime now) {
+        return schedulerJobDAO.getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED)
+                .stream()
+                .filter(canSchedulerForTerminatingBeApplied(now))
+                .collect(Collectors.toList());
+    }
+
+    private List<SchedulerJobData> getComputationalSchedulersForTerminating(OffsetDateTime now) {
+        return schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(RUNNING, STOPPED, RUNNING)
+                .stream()
+                .filter(canSchedulerForTerminatingBeApplied(now))
+                .collect(Collectors.toList());
+    }
+
+    private void startExploratory(SchedulerJobData schedulerJobData) {
+        final String user = schedulerJobData.getUser();
+        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, String.format(AUDIT_MESSAGE, exploratoryName));
+        if (schedulerJobData.getJobDTO().isSyncStartRequired()) {
+            log.trace("Starting computational for exploratory {} for user {} by scheduler", exploratoryName, user);
+            final DataEngineType sparkCluster = DataEngineType.SPARK_STANDALONE;
+            final List<UserComputationalResource> compToBeStarted =
+                    computationalDAO.findComputationalResourcesWithStatus(user, project, exploratoryName, STOPPED);
+
+            compToBeStarted
+                    .stream()
+                    .filter(compResource -> shouldClusterBeStarted(sparkCluster, compResource))
+                    .forEach(comp -> startSpark(user, exploratoryName, comp.getComputationalName(), project));
+        }
+    }
+
+    private void terminateExploratory(SchedulerJobData job) {
+        final String user = job.getUser();
+        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), user, project, expName, String.format(AUDIT_MESSAGE, expName));
+    }
+
+    private void startSpark(String user, String expName, String compName, String project) {
+        log.debug("Starting exploratory {} computational {} for user {} by scheduler", expName, compName, user);
+        computationalService.startSparkCluster(securityService.getServiceAccountInfo(user), expName, compName, project, String.format(AUDIT_MESSAGE, expName));
+    }
+
+    private boolean shouldClusterBeStarted(DataEngineType sparkCluster, UserComputationalResource compResource) {
+        return Objects.nonNull(compResource.getSchedulerData()) && compResource.getSchedulerData().isSyncStartRequired()
+                && compResource.getImageName().equals(getDockerImageName(sparkCluster));
+    }
+
+    /**
+     * Performs bulk updating operation with scheduler data for corresponding to exploratory Spark clusters.
+     * All these resources will obtain data which is equal to exploratory's except 'stopping' operation (it will be
+     * performed automatically with notebook stopping since Spark resources have such feature).
+     *
+     * @param user            user's name
+     * @param project         project name
+     * @param exploratoryName name of exploratory resource
+     * @param dto             scheduler job data.
+     */
+    private void shareSchedulerJobDataToSparkClusters(String user, String project, String exploratoryName, SchedulerJobDTO dto) {
+        List<String> correspondingSparkClusters = computationalDAO.getComputationalResourcesWhereStatusIn(user, project,
+                singletonList(DataEngineType.SPARK_STANDALONE),
+                exploratoryName, STARTING, RUNNING, STOPPING, STOPPED);
+        SchedulerJobDTO dtoWithoutStopData = getSchedulerJobWithoutStopData(dto);
+        for (String sparkName : correspondingSparkClusters) {
+            log.debug("Updating computational resource {} affiliated with exploratory {} for user {} with new " +
+                    "scheduler job data {}...", sparkName, exploratoryName, user, dtoWithoutStopData);
+            computationalDAO.updateSchedulerDataForComputationalResource(user, project, exploratoryName,
+                    sparkName, dtoWithoutStopData);
+        }
+    }
+
+    private List<SchedulerJobData> getExploratorySchedulersForStopping(OffsetDateTime currentDateTime) {
+        return schedulerJobDAO.getExploratorySchedulerDataWithStatus(RUNNING)
+                .stream()
+                .filter(canSchedulerForStoppingBeApplied(currentDateTime, true))
+                .collect(Collectors.toList());
+    }
+
+    private List<SchedulerJobData> getExploratorySchedulersForStopping(OffsetDateTime currentDateTime,
+                                                                       boolean checkInactivity) {
+        final Date clusterMaxInactivityAllowedDate =
+                from(LocalDateTime.now().minusMinutes(ALLOWED_INACTIVITY_MINUTES).atZone(systemDefault()).toInstant());
+        return schedulerJobDAO.getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(RUNNING,
+                clusterMaxInactivityAllowedDate)
+                .stream()
+                .filter(canSchedulerForStoppingBeApplied(currentDateTime, false)
+                        .or(schedulerJobData -> checkInactivity && exploratoryInactivityCondition(schedulerJobData)))
+                .collect(Collectors.toList());
+    }
+
+    private List<SchedulerJobData> getExploratorySchedulersForStarting(OffsetDateTime currentDateTime) {
+        return schedulerJobDAO.getExploratorySchedulerDataWithStatus(STOPPED)
+                .stream()
+                .filter(canSchedulerForStartingBeApplied(currentDateTime))
+                .collect(Collectors.toList());
+    }
+
+    private List<SchedulerJobData> getComputationalSchedulersForStarting(OffsetDateTime currentDateTime) {
+        return schedulerJobDAO
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, STOPPED)
+                .stream()
+                .filter(canSchedulerForStartingBeApplied(currentDateTime))
+                .collect(Collectors.toList());
+    }
+
+    private Predicate<SchedulerJobData> canSchedulerForStoppingBeApplied(OffsetDateTime currentDateTime, boolean usingOffset) {
+        return schedulerJobData -> shouldSchedulerBeExecuted(schedulerJobData.getJobDTO(),
+                currentDateTime, schedulerJobData.getJobDTO().getStopDaysRepeat(),
+                schedulerJobData.getJobDTO().getEndTime(), usingOffset);
+    }
+
+    private Predicate<SchedulerJobData> canSchedulerForStartingBeApplied(OffsetDateTime currentDateTime) {
+        return schedulerJobData -> shouldSchedulerBeExecuted(schedulerJobData.getJobDTO(),
+                currentDateTime, schedulerJobData.getJobDTO().getStartDaysRepeat(),
+                schedulerJobData.getJobDTO().getStartTime(), false);
+    }
+
+    private Predicate<SchedulerJobData> canSchedulerForTerminatingBeApplied(OffsetDateTime currentDateTime) {
+        return schedulerJobData -> shouldBeTerminated(currentDateTime, schedulerJobData);
+    }
+
+    private boolean shouldBeTerminated(OffsetDateTime currentDateTime, SchedulerJobData schedulerJobData) {
+        final SchedulerJobDTO jobDTO = schedulerJobData.getJobDTO();
+        final ZoneOffset timeZoneOffset = jobDTO.getTimeZoneOffset();
+        final LocalDateTime convertedCurrentTime = localDateTimeAtZone(currentDateTime, timeZoneOffset);
+        final LocalDateTime terminateDateTime = jobDTO.getTerminateDateTime();
+        return Objects.nonNull(terminateDateTime) && isSchedulerActive(jobDTO, convertedCurrentTime) &&
+                convertedCurrentTime.equals(terminateDateTime.atOffset(timeZoneOffset).toLocalDateTime());
+    }
+
+    private List<SchedulerJobData> getComputationalSchedulersForStopping(OffsetDateTime currentDateTime) {
+        return schedulerJobDAO
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING)
+                .stream()
+                .filter(canSchedulerForStoppingBeApplied(currentDateTime, true))
+                .collect(Collectors.toList());
+    }
+
+    private List<SchedulerJobData> getComputationalSchedulersForStopping(OffsetDateTime currentDateTime,
+                                                                         boolean checkInactivity) {
+        return schedulerJobDAO
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING)
+                .stream()
+                .filter(canSchedulerForStoppingBeApplied(currentDateTime, false)
+                        .or(schedulerJobData -> checkInactivity && computationalInactivityCondition(schedulerJobData)))
+                .collect(Collectors.toList());
+    }
+
+    private boolean computationalInactivityCondition(SchedulerJobData jobData) {
+        final SchedulerJobDTO schedulerData = jobData.getJobDTO();
+        return schedulerData.isCheckInactivityRequired() && computationalInactivityExceed(jobData, schedulerData);
+    }
+
+    private boolean computationalInactivityExceed(SchedulerJobData schedulerJobData, SchedulerJobDTO schedulerData) {
+        final String projectName = schedulerJobData.getProject();
+        final String explName = schedulerJobData.getExploratoryName();
+        final String compName = schedulerJobData.getComputationalName();
+        final String user = schedulerJobData.getUser();
+        final UserComputationalResource c = computationalDAO.fetchComputationalFields(user, projectName, explName, compName);
+        final Long maxInactivity = schedulerData.getMaxInactivity();
+        return inactivityCondition(maxInactivity, c.getStatus(), c.getLastActivity());
+    }
+
+    private boolean exploratoryInactivityCondition(SchedulerJobData jobData) {
+        final SchedulerJobDTO schedulerData = jobData.getJobDTO();
+        return schedulerData.isCheckInactivityRequired() && exploratoryInactivityExceed(jobData, schedulerData);
+    }
+
+    private boolean exploratoryInactivityExceed(SchedulerJobData schedulerJobData, SchedulerJobDTO schedulerData) {
+        final String project = schedulerJobData.getProject();
+        final String expName = schedulerJobData.getExploratoryName();
+        final String user = schedulerJobData.getUser();
+        final UserInstanceDTO userInstanceDTO = exploratoryDAO.fetchExploratoryFields(user, project, expName, true);
+        final boolean canBeStopped = userInstanceDTO.getResources()
+                .stream()
+                .map(UserComputationalResource::getStatus)
+                .map(UserInstanceStatus::of)
+                .noneMatch(status -> status.in(TERMINATING, CONFIGURING, CREATING, CREATING));
+        return canBeStopped && inactivityCondition(schedulerData.getMaxInactivity(), userInstanceDTO.getStatus(),
+                userInstanceDTO.getLastActivity());
+    }
+
+    private boolean inactivityCondition(Long maxInactivity, String status, LocalDateTime lastActivity) {
+        return UserInstanceStatus.RUNNING.toString().equals(status) &&
+                Optional.ofNullable(lastActivity)
+                        .map(la -> la.plusMinutes(maxInactivity).isBefore(LocalDateTime.now()))
+                        .orElse(Boolean.FALSE);
+    }
+
+    private void populateDefaultSchedulerValues(SchedulerJobDTO dto) {
+        if (Objects.isNull(dto.getBeginDate()) || StringUtils.isBlank(dto.getBeginDate().toString())) {
+            dto.setBeginDate(LocalDate.now());
+        }
+        if (Objects.isNull(dto.getTimeZoneOffset()) || StringUtils.isBlank(dto.getTimeZoneOffset().toString())) {
+            dto.setTimeZoneOffset(OffsetDateTime.now(systemDefault()).getOffset());
+        }
+    }
+
+    private void validateExploratoryStatus(String user, String project, String exploratoryName) {
+        final UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(user, project, exploratoryName);
+        validateResourceStatus(userInstance.getStatus());
+    }
+
+    private void validateComputationalStatus(String user, String project, String exploratoryName, String computationalName) {
+        final UserComputationalResource computationalResource =
+                computationalDAO.fetchComputationalFields(user, project, exploratoryName, computationalName);
+        final String computationalStatus = computationalResource.getStatus();
+        validateResourceStatus(computationalStatus);
+    }
+
+    private void validateResourceStatus(String resourceStatus) {
+        final UserInstanceStatus status = UserInstanceStatus.of(resourceStatus);
+        if (Objects.isNull(status) || status.in(UserInstanceStatus.TERMINATED, TERMINATING,
+                UserInstanceStatus.FAILED)) {
+            throw new ResourceInappropriateStateException(String.format("Can not create/update scheduler for user " +
+                    "instance with status: %s", status));
+        }
+    }
+
+    private boolean shouldSchedulerBeExecuted(SchedulerJobDTO dto, OffsetDateTime dateTime, List<DayOfWeek> daysRepeat,
+                                              LocalTime time, boolean usingOffset) {
+        ZoneOffset timeZoneOffset = dto.getTimeZoneOffset();
+        LocalDateTime convertedDateTime = localDateTimeAtZone(dateTime, timeZoneOffset);
+        return isSchedulerActive(dto, convertedDateTime)
+                && daysRepeat.contains(convertedDateTime.toLocalDate().getDayOfWeek())
+                && timeFilter(time, convertedDateTime.toLocalTime(), timeZoneOffset, usingOffset);
+    }
+
+    private boolean timeFilter(LocalTime time, LocalTime convertedDateTime, ZoneOffset timeZoneOffset, boolean usingOffset) {
+        return usingOffset ? (time.isBefore(convertedDateTime) && time.isAfter(LocalDateTime.now(timeZoneOffset).toLocalTime())) :
+                convertedDateTime.equals(time);
+    }
+
+    private boolean isSchedulerActive(SchedulerJobDTO dto, LocalDateTime convertedDateTime) {
+        return !convertedDateTime.toLocalDate().isBefore(dto.getBeginDate())
+                && finishDateAfterCurrentDate(dto, convertedDateTime);
+    }
+
+    private LocalDateTime localDateTimeAtZone(OffsetDateTime dateTime, ZoneOffset timeZoneOffset) {
+        return dateTime.atZoneSameInstant(ZoneOffset.UTC)
+                .truncatedTo(ChronoUnit.MINUTES)
+                .withZoneSameInstant(timeZoneOffset)
+                .toLocalDateTime();
+    }
+
+    private boolean finishDateAfterCurrentDate(SchedulerJobDTO dto, LocalDateTime currentDateTime) {
+        return Objects.isNull(dto.getFinishDate()) || !currentDateTime.toLocalDate().isAfter(dto.getFinishDate());
+    }
+
+    private SchedulerJobDTO getSchedulerJobWithoutStopData(SchedulerJobDTO dto) {
+        SchedulerJobDTO convertedDto = new SchedulerJobDTO();
+        convertedDto.setBeginDate(dto.getBeginDate());
+        convertedDto.setFinishDate(dto.getFinishDate());
+        convertedDto.setStartTime(dto.getStartTime());
+        convertedDto.setStartDaysRepeat(dto.getStartDaysRepeat());
+        convertedDto.setTerminateDateTime(dto.getTerminateDateTime());
+        convertedDto.setTimeZoneOffset(dto.getTimeZoneOffset());
+        convertedDto.setSyncStartRequired(dto.isSyncStartRequired());
+        return convertedDto;
+    }
+
+}
+
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/SystemInfoServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/SystemInfoServiceImpl.java
new file mode 100644
index 0000000..9a8e064
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/SystemInfoServiceImpl.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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.resources.dto.SystemInfoDto;
+import com.epam.datalab.backendapi.service.SystemInfoService;
+import com.epam.datalab.model.systeminfo.DiskInfo;
+import com.epam.datalab.model.systeminfo.MemoryInfo;
+import com.epam.datalab.model.systeminfo.OsInfo;
+import com.epam.datalab.model.systeminfo.ProcessorInfo;
+import com.google.inject.Inject;
+import oshi.SystemInfo;
+import oshi.hardware.CentralProcessor;
+import oshi.hardware.GlobalMemory;
+import oshi.hardware.HardwareAbstractionLayer;
+import oshi.software.os.OperatingSystem;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class SystemInfoServiceImpl implements SystemInfoService {
+
+    @Inject
+    private SystemInfo si;
+
+    @Override
+    public SystemInfoDto getSystemInfo() {
+        HardwareAbstractionLayer hal = si.getHardware();
+        final OperatingSystem operatingSystem = si.getOperatingSystem();
+        return new SystemInfoDto(getOsInfo(operatingSystem), getProcessorInfo(hal), getMemoryInfo(hal),
+                getDiskInfoList(File.listRoots()));
+    }
+
+    private OsInfo getOsInfo(OperatingSystem os) {
+        return OsInfo.builder()
+                .manufacturer(os.getManufacturer())
+                .family(os.getFamily())
+                .version(os.getVersion().getVersion())
+                .buildNumber(os.getVersion().getBuildNumber())
+                .build();
+    }
+
+    private ProcessorInfo getProcessorInfo(HardwareAbstractionLayer hal) {
+        CentralProcessor cp = hal.getProcessor();
+        return ProcessorInfo.builder()
+                .model(cp.getModel())
+                .family(cp.getFamily())
+                .name(cp.getName())
+                .id(cp.getProcessorID())
+                .vendor(cp.getVendor())
+                .logicalCoreCount(cp.getLogicalProcessorCount())
+                .physicalCoreCount(cp.getPhysicalProcessorCount())
+                .isCpu64Bit(cp.isCpu64bit())
+                .currentSystemLoad(cp.getSystemCpuLoad())
+                .systemLoadAverage(cp.getSystemLoadAverage())
+                .build();
+    }
+
+    private MemoryInfo getMemoryInfo(HardwareAbstractionLayer hal) {
+        GlobalMemory memory = hal.getMemory();
+        return MemoryInfo.builder()
+                .availableMemory(memory.getAvailable())
+                .totalMemory(memory.getTotal())
+                .swapTotal(memory.getSwapTotal())
+                .swapUsed(memory.getSwapUsed())
+                .pagesPageIn(memory.getSwapPagesIn())
+                .pagesPageOut(memory.getSwapPagesOut())
+                .build();
+    }
+
+    private List<DiskInfo> getDiskInfoList(File[] roots) {
+        return Arrays.stream(roots).map(this::getDiskInfo).collect(Collectors.toList());
+    }
+
+    private DiskInfo getDiskInfo(File fileStore) {
+        return DiskInfo.builder()
+                .serialNumber(fileStore.getName())
+                .usedByteSpace(fileStore.getTotalSpace() - fileStore.getFreeSpace())
+                .totalByteSpace(fileStore.getTotalSpace())
+                .build();
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/UserGroupServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/UserGroupServiceImpl.java
new file mode 100644
index 0000000..8ce5afe
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/UserGroupServiceImpl.java
@@ -0,0 +1,228 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Audit;
+import com.epam.datalab.backendapi.annotation.ResourceName;
+import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.ProjectDAO;
+import com.epam.datalab.backendapi.dao.UserGroupDAO;
+import com.epam.datalab.backendapi.dao.UserRoleDAO;
+import com.epam.datalab.backendapi.domain.AuditDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.resources.dto.UserGroupDto;
+import com.epam.datalab.backendapi.resources.dto.UserRoleDto;
+import com.epam.datalab.backendapi.roles.UserRoles;
+import com.epam.datalab.backendapi.service.AuditService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.service.UserGroupService;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceConflictException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.CREATE;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.DELETE;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.UPDATE;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.GROUP;
+
+@Singleton
+@Slf4j
+public class UserGroupServiceImpl implements UserGroupService {
+    private static final String AUDIT_ADD_ROLE_MESSAGE = "Add role(s): %s\n";
+    private static final String AUDIT_REMOVE_ROLE_MESSAGE = "Remove role(s): %s\n";
+    private static final String AUDIT_ADD_USER_MESSAGE = "Add user(s): %s\n";
+    private static final String AUDIT_REMOVE_USER_MESSAGE = "Remove user(s): %s\n";
+    private static final String ROLE_NOT_FOUND_MSG = "Any of role : %s were not found";
+    private static final String ADMIN = "admin";
+    private static final String PROJECT_ADMIN = "projectAdmin";
+    private static final String INAPPROPRIATE_PERMISSION = "User %s doesn't have appropriate permission";
+
+    private final UserGroupDAO userGroupDao;
+    private final UserRoleDAO userRoleDao;
+    private final ProjectDAO projectDAO;
+    private final ProjectService projectService;
+    private final AuditService auditService;
+    private final SelfServiceApplicationConfiguration configuration;
+
+    @Inject
+    public UserGroupServiceImpl(UserGroupDAO userGroupDao, UserRoleDAO userRoleDao, ProjectDAO projectDAO, ProjectService projectService, AuditService auditService,
+                                SelfServiceApplicationConfiguration configuration) {
+        this.userGroupDao = userGroupDao;
+        this.userRoleDao = userRoleDao;
+        this.projectDAO = projectDAO;
+        this.projectService = projectService;
+        this.auditService = auditService;
+        this.configuration = configuration;
+    }
+
+    @Audit(action = CREATE, type = GROUP)
+    @Override
+    public void createGroup(@User UserInfo userInfo, @ResourceName String group, Set<String> roleIds, Set<String> users) {
+        checkAnyRoleFound(roleIds, userRoleDao.addGroupToRole(Collections.singleton(group), roleIds));
+        log.debug("Adding users {} to group {}", users, group);
+        userGroupDao.addUsers(group, users);
+    }
+
+    @Override
+    public void updateGroup(UserInfo userInfo, String group, Map<String, String> roles, Set<String> users) {
+        if (UserRoles.isAdmin(userInfo)) {
+            updateGroup(userInfo.getName(), group, roles, users);
+        } else if (UserRoles.isProjectAdmin(userInfo)) {
+            projectService.getProjects(userInfo)
+                    .stream()
+                    .map(ProjectDTO::getGroups)
+                    .flatMap(Collection::stream)
+                    .filter(g -> g.equalsIgnoreCase(group))
+                    .findAny()
+                    .orElseThrow(() -> new DatalabException(String.format(INAPPROPRIATE_PERMISSION, userInfo.getName())));
+            updateGroup(userInfo.getName(), group, roles, users);
+        } else {
+            throw new DatalabException(String.format(INAPPROPRIATE_PERMISSION, userInfo.getName()));
+        }
+    }
+
+    @Audit(action = DELETE, type = GROUP)
+    @Override
+    public void removeGroup(@User UserInfo userInfo, @ResourceName String groupId) {
+        if (projectDAO.getProjectsWithEndpointStatusNotIn(UserInstanceStatus.TERMINATED,
+                UserInstanceStatus.TERMINATING)
+                .stream()
+                .map(ProjectDTO::getGroups)
+                .noneMatch(groups -> groups.contains(groupId))) {
+            userRoleDao.removeGroup(groupId);
+            userGroupDao.removeGroup(groupId);
+        } else {
+            throw new ResourceConflictException("Group can not be removed because it is used in some project");
+        }
+    }
+
+    @Override
+    public List<UserGroupDto> getAggregatedRolesByGroup(UserInfo user) {
+        if (UserRoles.isAdmin(user)) {
+            return userRoleDao.aggregateRolesByGroup();
+        } else if (UserRoles.isProjectAdmin(user)) {
+            Set<String> groups = projectService.getProjects(user)
+                    .stream()
+                    .map(ProjectDTO::getGroups)
+                    .flatMap(Collection::stream)
+                    .collect(Collectors.toSet());
+            return userRoleDao.aggregateRolesByGroup()
+                    .stream()
+                    .filter(userGroup -> groups.contains(userGroup.getGroup()) && !containsAdministrationPermissions(userGroup))
+                    .collect(Collectors.toList());
+        } else {
+            throw new DatalabException(String.format(INAPPROPRIATE_PERMISSION, user.getName()));
+        }
+    }
+
+    private boolean containsAdministrationPermissions(UserGroupDto userGroup) {
+        List<String> ids = userGroup.getRoles()
+                .stream()
+                .map(UserRoleDto::getId)
+                .collect(Collectors.toList());
+        return ids.contains(ADMIN) || ids.contains(PROJECT_ADMIN);
+    }
+
+    private void updateGroup(String user, String group, Map<String, String> roles, Set<String> users) {
+        Set<String> roleIds = roles.keySet();
+        if (configuration.isAuditEnabled()) {
+            audit(user, group, roles, users);
+        }
+        log.debug("Updating users for group {}: {}", group, users);
+        userGroupDao.updateUsers(group, users);
+        log.debug("Removing group {} from existing roles", group);
+        userRoleDao.removeGroupWhenRoleNotIn(group, roleIds);
+        log.debug("Adding group {} to roles {}", group, roleIds);
+        userRoleDao.addGroupToRole(Collections.singleton(group), roleIds);
+    }
+
+    private void audit(String user, String group, Map<String, String> newRoles, Set<String> users) {
+        final String auditInfo = roleAudit(group, newRoles) + getUserAudit(group, users);
+        AuditDTO auditDTO = AuditDTO.builder()
+                .user(user)
+                .resourceName(group)
+                .action(UPDATE)
+                .type(GROUP)
+                .info(auditInfo)
+                .build();
+        auditService.save(auditDTO);
+    }
+
+    private String getUserAudit(String group, Set<String> users) {
+        StringBuilder auditInfo = new StringBuilder();
+        Set<String> oldUsers = userGroupDao.getUsers(group);
+        HashSet<String> newUsers = new HashSet<>(users);
+        newUsers.removeAll(oldUsers);
+        if (!newUsers.isEmpty()) {
+            auditInfo.append(String.format(AUDIT_ADD_USER_MESSAGE, String.join(", ", newUsers)));
+        }
+        HashSet<String> removedUsers = new HashSet<>(oldUsers);
+        removedUsers.removeAll(users);
+        if (!removedUsers.isEmpty()) {
+            auditInfo.append(String.format(AUDIT_REMOVE_USER_MESSAGE, String.join(", ", removedUsers)));
+        }
+        return auditInfo.toString();
+    }
+
+    private String roleAudit(String group, Map<String, String> newRoles) {
+        StringBuilder auditInfo = new StringBuilder();
+        Map<String, String> oldRoles = userRoleDao.aggregateRolesByGroup()
+                .stream()
+                .filter(g -> g.getGroup().equals(group))
+                .map(UserGroupDto::getRoles)
+                .flatMap(Collection::stream)
+                .collect(Collectors.toMap(UserRoleDto::getId, UserRoleDto::getDescription));
+        if (!getRoleDescription(oldRoles, newRoles).isEmpty()) {
+            auditInfo.append(String.format(AUDIT_ADD_ROLE_MESSAGE, getRoleDescription(oldRoles, newRoles)));
+        }
+        if (!getRoleDescription(newRoles, oldRoles).isEmpty()) {
+            auditInfo.append(String.format(AUDIT_REMOVE_ROLE_MESSAGE, getRoleDescription(newRoles, oldRoles)));
+        }
+        return auditInfo.toString();
+    }
+
+    private String getRoleDescription(Map<String, String> newRoles, Map<String, String> oldRoles) {
+        Set<String> removedRoleIds = new HashSet<>(oldRoles.keySet());
+        removedRoleIds.removeAll(newRoles.keySet());
+        return removedRoleIds
+                .stream()
+                .map(oldRoles::get)
+                .collect(Collectors.joining(", "));
+    }
+
+    private void checkAnyRoleFound(Set<String> roleIds, boolean anyRoleFound) {
+        if (!anyRoleFound) {
+            throw new ResourceNotFoundException(String.format(ROLE_NOT_FOUND_MSG, roleIds));
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/servlet/guacamole/GuacamoleServlet.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/servlet/guacamole/GuacamoleServlet.java
new file mode 100644
index 0000000..3ca5557
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/servlet/guacamole/GuacamoleServlet.java
@@ -0,0 +1,97 @@
+/*
+ * 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.datalab.backendapi.servlet.guacamole;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.SecurityDAO;
+import com.epam.datalab.backendapi.service.GuacamoleService;
+import com.epam.datalab.exceptions.DatalabAuthenticationException;
+import com.epam.datalab.exceptions.DatalabException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.guacamole.net.GuacamoleTunnel;
+import org.apache.guacamole.servlet.GuacamoleHTTPTunnelServlet;
+import org.apache.http.HttpStatus;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.HttpHeaders;
+import java.io.IOException;
+
+@Slf4j
+public class GuacamoleServlet extends GuacamoleHTTPTunnelServlet {
+	private static final String UNAUTHORIZED_MSG = "User is not authenticated";
+	private static final String DATALAB_PREFIX = "DataLab-";
+	private final GuacamoleService guacamoleService;
+	private final ObjectMapper mapper;
+	private final SecurityDAO securityDAO;
+	private static final String AUTH_HEADER_PREFIX = "Bearer ";
+
+	@Inject
+	public GuacamoleServlet(GuacamoleService guacamoleService, ObjectMapper mapper, SecurityDAO securityDAO) {
+		this.mapper = mapper;
+		this.guacamoleService = guacamoleService;
+		this.securityDAO = securityDAO;
+	}
+
+	@Override
+	protected GuacamoleTunnel doConnect(HttpServletRequest request) {
+		try {
+			final String authorization = request.getHeader(DATALAB_PREFIX + HttpHeaders.AUTHORIZATION);
+			final String credentials = StringUtils.substringAfter(authorization, AUTH_HEADER_PREFIX);
+			final UserInfo userInfo = getUserInfo(credentials);
+			final CreateTerminalDTO createTerminalDTO = mapper.readValue(request.getReader(), CreateTerminalDTO.class);
+			return guacamoleService.getTunnel(userInfo, createTerminalDTO.getHost(), createTerminalDTO.getEndpoint());
+		} catch (IOException e) {
+			log.error("Cannot read request body. Reason {}", e.getMessage(), e);
+			throw new DatalabException("Can not read request body: " + e.getMessage(), e);
+		}
+	}
+
+	@Override
+	protected void handleTunnelRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException {
+		try {
+			super.handleTunnelRequest(request, response);
+		} catch (DatalabAuthenticationException e) {
+			log.error(UNAUTHORIZED_MSG, e);
+			sendError(response, HttpStatus.SC_UNAUTHORIZED, HttpStatus.SC_UNAUTHORIZED, UNAUTHORIZED_MSG);
+		}
+	}
+
+	private UserInfo getUserInfo(String credentials) {
+		try {
+			return securityDAO.getUser(credentials)
+					.orElseThrow(() -> new DatalabAuthenticationException(UNAUTHORIZED_MSG));
+		} catch (DatalabAuthenticationException e) {
+			log.error(UNAUTHORIZED_MSG, e);
+			throw new DatalabException(UNAUTHORIZED_MSG);
+		}
+	}
+
+	@Data
+	private static class CreateTerminalDTO {
+		private String host;
+		private String endpoint;
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/util/BillingUtils.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/BillingUtils.java
new file mode 100644
index 0000000..80aa9b4
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/BillingUtils.java
@@ -0,0 +1,249 @@
+/*
+ * 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.datalab.backendapi.util;
+
+import com.epam.datalab.backendapi.domain.BillingReportLine;
+import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import jersey.repackaged.com.google.common.collect.Lists;
+import org.apache.commons.lang3.StringUtils;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import static com.epam.datalab.dto.billing.BillingResourceType.BUCKET;
+import static com.epam.datalab.dto.billing.BillingResourceType.COMPUTATIONAL;
+import static com.epam.datalab.dto.billing.BillingResourceType.EDGE;
+import static com.epam.datalab.dto.billing.BillingResourceType.ENDPOINT;
+import static com.epam.datalab.dto.billing.BillingResourceType.EXPLORATORY;
+import static com.epam.datalab.dto.billing.BillingResourceType.IMAGE;
+import static com.epam.datalab.dto.billing.BillingResourceType.SSN;
+import static com.epam.datalab.dto.billing.BillingResourceType.VOLUME;
+
+public class BillingUtils {
+    private static final String[] AVAILABLE_NOTEBOOKS = {"zeppelin", "tensor-rstudio", "rstudio", "tensor", "superset", "jupyterlab", "jupyter", "deeplearning"};
+    private static final String[] BILLING_FILTERED_REPORT_HEADERS = {"DataLab ID", "Project", "DataLab Resource Type", "Status", "Shape", "Product", "Cost"};
+    private static final String[] COMPLETE_REPORT_REPORT_HEADERS = {"DataLab ID", "User", "Project", "DataLab Resource Type", "Status", "Shape", "Product", "Cost"};
+    private static final String REPORT_FIRST_LINE = "Service base name: %s. Available reporting period from: %s to: %s";
+    private static final String TOTAL_LINE = "Total: %s %s";
+    private static final String SSN_FORMAT = "%s-ssn";
+    private static final String ENDPOINT_FORMAT = "%s-%s-endpoint";
+    private static final String EDGE_FORMAT = "%s-%s-%s-edge";
+    private static final String EDGE_VOLUME_FORMAT = "%s-%s-%s-edge-volume-primary";
+    private static final String PROJECT_ENDPOINT_BUCKET_FORMAT = "%s-%s-%s-bucket";
+    private static final String ENDPOINT_SHARED_BUCKET_FORMAT = "%s-%s-shared-bucket";
+    private static final String VOLUME_PRIMARY_FORMAT = "%s-volume-primary";
+    private static final String VOLUME_PRIMARY_COMPUTATIONAL_FORMAT = "%s-%s-volume-primary";
+    private static final String VOLUME_SECONDARY_FORMAT = "%s-volume-secondary";
+    private static final String VOLUME_SECONDARY_COMPUTATIONAL_FORMAT = "%s-%s-volume-secondary";
+    private static final String IMAGE_STANDARD_FORMAT1 = "%s-%s-%s-%s-notebook-image";
+    private static final String IMAGE_STANDARD_FORMAT2 = "%s-%s-%s-notebook-image";
+    private static final String IMAGE_CUSTOM_FORMAT = "%s-%s-%s-%s-%s";
+
+    private static final String SHARED_RESOURCE = "Shared resource";
+    private static final String IMAGE_NAME = "Image";
+
+    private static final String DATAENGINE_NAME_FORMAT = "%d x %s";
+    private static final String DATAENGINE_SERVICE_NAME_FORMAT = "Master: %sSlave: %d x %s";
+
+    public static Stream<BillingReportLine> edgeBillingDataStream(String project, String sbn, String endpoint) {
+        final String userEdgeId = String.format(EDGE_FORMAT, sbn, project, endpoint).toLowerCase();
+        final String edgeVolumeId = String.format(EDGE_VOLUME_FORMAT, sbn, project, endpoint).toLowerCase();
+        final String endpointBucketId = String.format(PROJECT_ENDPOINT_BUCKET_FORMAT, sbn, project, endpoint).toLowerCase();
+
+        return Stream.concat(Stream.of(
+                BillingReportLine.builder().resourceName(endpoint).user(SHARED_RESOURCE).project(project).datalabId(userEdgeId).resourceType(EDGE).build(),
+                BillingReportLine.builder().resourceName("EDGE volume").user(SHARED_RESOURCE).project(project).datalabId(edgeVolumeId).resourceType(VOLUME).build(),
+                BillingReportLine.builder().resourceName("Project endpoint shared bucket").user(SHARED_RESOURCE).project(project).datalabId(endpointBucketId).resourceType(BUCKET).build()
+                ),
+                standardImageBillingDataStream(sbn, project, endpoint)
+        );
+    }
+
+    public static Stream<BillingReportLine> ssnBillingDataStream(String sbn) {
+        final String ssnId = String.format(SSN_FORMAT, sbn);
+        return Stream.of(
+                BillingReportLine.builder().user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceName("SSN").datalabId(ssnId).resourceType(SSN).build(),
+                BillingReportLine.builder().user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceName("SSN Volume").datalabId(String.format(VOLUME_PRIMARY_FORMAT, ssnId)).resourceType(VOLUME).build()
+        );
+    }
+
+    public static Stream<BillingReportLine> sharedEndpointBillingDataStream(String endpoint, String sbn) {
+        final String projectEndpointBucketId = String.format(ENDPOINT_SHARED_BUCKET_FORMAT, sbn, endpoint).toLowerCase();
+        final String endpointId = String.format(ENDPOINT_FORMAT, sbn, endpoint).toLowerCase();
+        return Stream.concat(Stream.of(
+                BillingReportLine.builder().resourceName("Endpoint shared bucket").user(SHARED_RESOURCE).project(SHARED_RESOURCE).datalabId(projectEndpointBucketId).resourceType(BUCKET).build(),
+                BillingReportLine.builder().resourceName("Endpoint").user(SHARED_RESOURCE).project(SHARED_RESOURCE).datalabId(endpointId).resourceType(ENDPOINT).build()
+                ),
+                standardImageBillingDataStream(sbn, endpoint));
+    }
+
+    public static Stream<BillingReportLine> exploratoryBillingDataStream(UserInstanceDTO userInstance, Integer maxSparkInstanceCount) {
+        final Stream<BillingReportLine> computationalStream = userInstance.getResources()
+                .stream()
+                .filter(cr -> cr.getComputationalId() != null)
+                .flatMap(cr -> {
+                    final String computationalId = cr.getComputationalId().toLowerCase();
+                    return Stream.concat(Stream.of(
+                            withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).datalabId(computationalId).resourceType(COMPUTATIONAL).shape(getComputationalShape(cr))
+                                    .exploratoryName(userInstance.getExploratoryName()).build(),
+                            withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).datalabId(String.format(VOLUME_PRIMARY_FORMAT, computationalId)).resourceType(VOLUME).build(),
+                            withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).datalabId(String.format(VOLUME_SECONDARY_FORMAT, computationalId)).resourceType(VOLUME).build(),
+                            withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).datalabId(String.format(VOLUME_PRIMARY_COMPUTATIONAL_FORMAT, computationalId, "m"))
+                                    .resourceType(VOLUME).build(),
+                            withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).datalabId(String.format(VOLUME_SECONDARY_COMPUTATIONAL_FORMAT, computationalId, "m"))
+                                    .resourceType(VOLUME).build()
+                            ),
+                            getSlaveVolumes(userInstance, cr, maxSparkInstanceCount)
+                    );
+                });
+        final String exploratoryName = userInstance.getExploratoryName();
+        final String exploratoryId = userInstance.getExploratoryId().toLowerCase();
+        final String primaryVolumeId = String.format(VOLUME_PRIMARY_FORMAT, exploratoryId);
+        final String secondaryVolumeId = String.format(VOLUME_SECONDARY_FORMAT, exploratoryId);
+        final Stream<BillingReportLine> exploratoryStream = Stream.of(
+                withUserProjectEndpoint(userInstance).resourceName(exploratoryName).datalabId(exploratoryId).resourceType(EXPLORATORY).shape(userInstance.getShape()).build(),
+                withUserProjectEndpoint(userInstance).resourceName(exploratoryName).datalabId(primaryVolumeId).resourceType(VOLUME).build(),
+                withUserProjectEndpoint(userInstance).resourceName(exploratoryName).datalabId(secondaryVolumeId).resourceType(VOLUME).build());
+
+        return Stream.concat(computationalStream, exploratoryStream);
+    }
+
+    public static Stream<BillingReportLine> customImageBillingDataStream(ImageInfoRecord image, String sbn) {
+        String imageId = String.format(IMAGE_CUSTOM_FORMAT, sbn, image.getProject(), image.getEndpoint(), image.getApplication(), image.getName()).toLowerCase();
+        return Stream.of(
+                BillingReportLine.builder().resourceName(image.getName()).project(image.getProject()).datalabId(imageId).user(image.getUser()).resourceType(IMAGE).build()
+        );
+    }
+
+    private static Stream<BillingReportLine> getSlaveVolumes(UserInstanceDTO userInstance, UserComputationalResource cr, Integer maxSparkInstanceCount) {
+        List<BillingReportLine> list = new ArrayList<>();
+        for (int i = 1; i <= maxSparkInstanceCount; i++) {
+            list.add(withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).datalabId(String.format(VOLUME_PRIMARY_COMPUTATIONAL_FORMAT, cr.getComputationalId().toLowerCase(), "s" + i))
+                    .resourceType(VOLUME).build());
+            list.add(withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).datalabId(String.format(VOLUME_SECONDARY_COMPUTATIONAL_FORMAT, cr.getComputationalId().toLowerCase(), "s" + i))
+                    .resourceType(VOLUME).build());
+        }
+        return list.stream();
+    }
+
+    private static BillingReportLine.BillingReportLineBuilder withUserProjectEndpoint(UserInstanceDTO userInstance) {
+        return BillingReportLine.builder().user(userInstance.getUser()).project(userInstance.getProject()).endpoint(userInstance.getEndpoint());
+    }
+
+    public static String getComputationalShape(UserComputationalResource resource) {
+        return DataEngineType.fromDockerImageName(resource.getImageName()) == DataEngineType.SPARK_STANDALONE ?
+                String.format(DATAENGINE_NAME_FORMAT, resource.getDataengineInstanceCount(), resource.getDataengineShape()) :
+                String.format(DATAENGINE_SERVICE_NAME_FORMAT, resource.getMasterNodeShape(), resource.getTotalInstanceCount() - 1, resource.getSlaveNodeShape());
+    }
+
+    private static Stream<BillingReportLine> standardImageBillingDataStream(String sbn, String endpoint) {
+        List<BillingReportLine> list = new ArrayList<>();
+        for (String notebook : AVAILABLE_NOTEBOOKS) {
+            list.add(BillingReportLine.builder().resourceName(IMAGE_NAME).datalabId(String.format(IMAGE_STANDARD_FORMAT2, sbn, endpoint, notebook).toLowerCase())
+                    .user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceType(IMAGE).build());
+        }
+
+        return list.stream();
+    }
+
+    private static Stream<BillingReportLine> standardImageBillingDataStream(String sbn, String project, String endpoint) {
+        List<BillingReportLine> list = new ArrayList<>();
+        for (String notebook : AVAILABLE_NOTEBOOKS) {
+            list.add(BillingReportLine.builder().resourceName(IMAGE_NAME).datalabId(String.format(IMAGE_STANDARD_FORMAT1, sbn, project, endpoint, notebook).toLowerCase())
+                    .project(project).user(SHARED_RESOURCE).resourceType(IMAGE).build());
+        }
+
+        return list.stream();
+    }
+
+    /**
+     * @param sbn  Service Base Name
+     * @param from formatted date, like 2020-04-07
+     * @param to   formatted date, like 2020-05-07
+     * @return line, like:
+     * "Service base name: SERVICE_BASE_NAME. Available reporting period from: 2020-04-07 to: 2020-04-07"
+     */
+    public static String getFirstLine(String sbn, LocalDate from, LocalDate to) {
+        return CSVFormatter.formatLine(Lists.newArrayList(String.format(REPORT_FIRST_LINE, sbn,
+                Optional.ofNullable(from).map(date -> date.format(DateTimeFormatter.ISO_DATE)).orElse(StringUtils.EMPTY),
+                Optional.ofNullable(to).map(date -> date.format(DateTimeFormatter.ISO_DATE)).orElse(StringUtils.EMPTY))),
+                CSVFormatter.SEPARATOR, '\"');
+    }
+
+    /**
+     * headerType there are two types of header according user role
+     *
+     * @return line, like DataLab ID,User,Project,DataLab Resource Type,Status,Shape,Product,Cost
+     * in case of additional header type, the ENUM object will be propagated from the Service Impl Class
+     */
+    public static String getHeader(boolean isReportHeaderCompletable) {
+        if (!isReportHeaderCompletable) {
+            return CSVFormatter.formatLine(Arrays.asList(BillingUtils.BILLING_FILTERED_REPORT_HEADERS), CSVFormatter.SEPARATOR);
+        }
+        return CSVFormatter.formatLine(Arrays.asList(BillingUtils.COMPLETE_REPORT_REPORT_HEADERS), CSVFormatter.SEPARATOR);
+    }
+
+    public static String printLine(BillingReportLine line, boolean isReportHeaderCompletable) {
+        List<String> lines = new ArrayList<>();
+        lines.add(getOrEmpty(line.getDatalabId()));
+        //if user does not have the billing role, the User field should not be present in report
+        if (isReportHeaderCompletable) {
+            lines.add(getOrEmpty(line.getUser()));
+        }
+        lines.add(getOrEmpty(line.getProject()));
+        lines.add(getOrEmpty(Optional.ofNullable(line.getResourceType()).map(r -> StringUtils.capitalize(r.toString().toLowerCase())).orElse(null)));
+        lines.add(getOrEmpty(Optional.ofNullable(line.getStatus()).map(UserInstanceStatus::toString).orElse(null)));
+        lines.add(getOrEmpty(line.getShape()));
+        lines.add(getOrEmpty(line.getProduct()));
+        lines.add(getOrEmpty(Optional.ofNullable(line.getCost()).map(String::valueOf).orElse(null)));
+        return CSVFormatter.formatLine(lines, CSVFormatter.SEPARATOR);
+    }
+
+    /**
+     * @param total                  monetary amount
+     * @param currency               user's currency
+     * @param stringOfAdjustedHeader filtered fields of report header
+     * @return line with cost of resources
+     */
+    public static String getTotal(Double total, String currency, String stringOfAdjustedHeader) {
+        List<String> totalLine = new ArrayList<>();
+        String[] headerFieldsList = stringOfAdjustedHeader.split(String.valueOf(CSVFormatter.SEPARATOR));
+        for (int i = 0; i < headerFieldsList.length - 1; i++) {
+            totalLine.add(StringUtils.EMPTY);
+        }
+        totalLine.add(headerFieldsList.length - 1, String.format(TOTAL_LINE, getOrEmpty(String.valueOf(total)), getOrEmpty(currency)));
+        return CSVFormatter.formatLine(totalLine, CSVFormatter.SEPARATOR);
+
+    }
+
+    private static String getOrEmpty(String s) {
+        return Objects.nonNull(s) ? s : StringUtils.EMPTY;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/util/CSVFormatter.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/CSVFormatter.java
new file mode 100644
index 0000000..b842022
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/CSVFormatter.java
@@ -0,0 +1,67 @@
+/*
+ * 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.datalab.backendapi.util;
+
+import java.util.List;
+
+public class CSVFormatter {
+    public static final char SEPARATOR = ',';
+
+    private CSVFormatter() {
+    }
+
+
+    public static String formatLine(List<String> values, char separator) {
+        boolean first = true;
+        StringBuilder builder = new StringBuilder();
+        for (String value : values) {
+            if (!first) {
+                builder.append(separator);
+            }
+            builder.append(followCsvStandard(value));
+            first = false;
+        }
+        return builder.append(System.lineSeparator()).toString();
+    }
+
+    public static String formatLine(List<String> values, char separator, char customQuote) {
+        boolean first = true;
+        StringBuilder builder = new StringBuilder();
+        for (String value : values) {
+            if (!first) {
+                builder.append(separator);
+            }
+            builder.append(customQuote).append(followCsvStandard(value)).append(customQuote);
+            first = false;
+        }
+        return builder.append(System.lineSeparator()).toString();
+    }
+
+    private static String followCsvStandard(String value) {
+
+        String result = value;
+        if (result.contains("\"")) {
+            result = result.replace("\"", "\"\"");
+        }
+        return result;
+
+    }
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/util/DateRemoverUtil.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/DateRemoverUtil.java
new file mode 100644
index 0000000..3e76a90
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/DateRemoverUtil.java
@@ -0,0 +1,40 @@
+/*
+ * 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.datalab.backendapi.util;
+
+/**
+ * Created on 3/15/2017.
+ */
+public class DateRemoverUtil {
+
+    private static final String ERROR_DATE_FORMAT = "\\[Error-\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\]:";
+    private static final String ERROR_WITHOUT_DATE_FORMAT = "\\[Error\\]:";
+
+    private DateRemoverUtil() {
+    }
+
+    public static String removeDateFormErrorMessage(String errorMessage, String errorDateFormat, String replaceWith) {
+        return errorMessage.replaceAll(errorDateFormat, replaceWith);
+    }
+
+    public static String removeDateFormErrorMessage(String errorMessage) {
+        return errorMessage.replaceAll(ERROR_DATE_FORMAT, ERROR_WITHOUT_DATE_FORMAT);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/util/KeycloakUtil.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/KeycloakUtil.java
new file mode 100644
index 0000000..14c1946
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/KeycloakUtil.java
@@ -0,0 +1,41 @@
+/*
+ * 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.datalab.backendapi.util;
+
+import com.epam.datalab.exceptions.DatalabException;
+import org.keycloak.common.util.Base64Url;
+import org.keycloak.representations.IDToken;
+import org.keycloak.util.JsonSerialization;
+
+public class KeycloakUtil {
+
+    public static IDToken parseToken(String encoded) {
+        try {
+            String[] parts = encoded.split("\\.");
+            if (parts.length < 2 || parts.length > 3) {
+                throw new IllegalArgumentException("Parsing error");
+            }
+            byte[] bytes = Base64Url.decode(parts[1]);
+            return JsonSerialization.readValue(bytes, IDToken.class);
+        } catch (Exception e) {
+            throw new DatalabException("Can not parse token due to: " + e.getMessage(), e);
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/util/RequestBuilder.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/RequestBuilder.java
new file mode 100644
index 0000000..8e0845d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/RequestBuilder.java
@@ -0,0 +1,653 @@
+/*
+ * 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.datalab.backendapi.util;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.SettingsDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.resources.dto.BackupFormDTO;
+import com.epam.datalab.backendapi.resources.dto.ComputationalCreateFormDTO;
+import com.epam.datalab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
+import com.epam.datalab.backendapi.resources.dto.aws.AwsComputationalCreateForm;
+import com.epam.datalab.backendapi.resources.dto.gcp.GcpComputationalCreateForm;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.LibListComputationalDTO;
+import com.epam.datalab.dto.LibListExploratoryDTO;
+import com.epam.datalab.dto.ResourceBaseDTO;
+import com.epam.datalab.dto.ResourceSysBaseDTO;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.aws.AwsCloudSettings;
+import com.epam.datalab.dto.aws.computational.AwsComputationalTerminateDTO;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.aws.computational.ComputationalCreateAws;
+import com.epam.datalab.dto.aws.computational.SparkComputationalCreateAws;
+import com.epam.datalab.dto.aws.exploratory.ExploratoryCreateAws;
+import com.epam.datalab.dto.azure.AzureCloudSettings;
+import com.epam.datalab.dto.azure.computational.SparkComputationalCreateAzure;
+import com.epam.datalab.dto.azure.exploratory.ExploratoryActionStartAzure;
+import com.epam.datalab.dto.azure.exploratory.ExploratoryActionStopAzure;
+import com.epam.datalab.dto.azure.exploratory.ExploratoryCreateAzure;
+import com.epam.datalab.dto.backup.EnvBackupDTO;
+import com.epam.datalab.dto.base.CloudSettings;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.epam.datalab.dto.computational.ComputationalCheckInactivityDTO;
+import com.epam.datalab.dto.computational.ComputationalClusterConfigDTO;
+import com.epam.datalab.dto.computational.ComputationalStartDTO;
+import com.epam.datalab.dto.computational.ComputationalStopDTO;
+import com.epam.datalab.dto.computational.ComputationalTerminateDTO;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.dto.exploratory.ExploratoryActionDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryCheckInactivityAction;
+import com.epam.datalab.dto.exploratory.ExploratoryCreateDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryImageDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
+import com.epam.datalab.dto.exploratory.LibInstallDTO;
+import com.epam.datalab.dto.exploratory.LibraryInstallDTO;
+import com.epam.datalab.dto.gcp.GcpCloudSettings;
+import com.epam.datalab.dto.gcp.computational.ComputationalCreateGcp;
+import com.epam.datalab.dto.gcp.computational.GcpComputationalTerminateDTO;
+import com.epam.datalab.dto.gcp.computational.SparkComputationalCreateGcp;
+import com.epam.datalab.dto.gcp.exploratory.ExploratoryCreateGcp;
+import com.epam.datalab.dto.project.ProjectActionDTO;
+import com.epam.datalab.dto.project.ProjectCreateDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.model.exploratory.Exploratory;
+import com.epam.datalab.util.UsernameUtils;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import static com.epam.datalab.cloud.CloudProvider.AWS;
+import static com.epam.datalab.cloud.CloudProvider.AZURE;
+import static com.epam.datalab.cloud.CloudProvider.GCP;
+
+@Singleton
+public class RequestBuilder {
+    private static final String UNSUPPORTED_CLOUD_PROVIDER_MESSAGE = "Unsupported cloud provider ";
+    private static final String AZURE_REFRESH_TOKEN_KEY = "refresh_token";
+
+    @Inject
+    private SelfServiceApplicationConfiguration configuration;
+    @Inject
+    private SettingsDAO settingsDAO;
+
+    private CloudSettings cloudSettings(String user, CloudProvider cloudProvider) {
+        switch (cloudProvider) {
+            case AWS:
+                return AwsCloudSettings.builder()
+                        .awsIamUser(user)
+                        .build();
+            case AZURE:
+                return AzureCloudSettings.builder()
+                        .azureIamUser(user).build();
+            case GCP:
+                return GcpCloudSettings.builder()
+                        .gcpIamUser(user).build();
+            default:
+                throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T extends ResourceBaseDTO<?>> T newResourceBaseDTO(String user, CloudProvider cloudProvider,
+                                                                Class<T> resourceClass) {
+        try {
+            return (T) resourceClass.newInstance()
+                    .withEdgeUserName(getEdgeUserName(user, cloudProvider))
+                    .withCloudSettings(cloudSettings(user, cloudProvider));
+        } catch (Exception e) {
+            throw new DatalabException("Cannot create instance of resource class " + resourceClass.getName() + ". " +
+                    e.getLocalizedMessage(), e);
+        }
+    }
+
+    private String getEdgeUserName(String user, CloudProvider cloudProvider) {
+        String edgeUser = UsernameUtils.removeDomain(user);
+        switch (cloudProvider) {
+            case GCP:
+                return adjustUserName(configuration.getMaxUserNameLength(), edgeUser);
+            case AWS:
+            case AZURE:
+                return edgeUser;
+            default:
+                throw new DatalabException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
+        }
+    }
+
+    private String adjustUserName(int maxLength, String userName) {
+        return userName.length() > maxLength ?
+                UUID.nameUUIDFromBytes(userName.getBytes()).toString().substring(0, maxLength) : userName;
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T extends ResourceSysBaseDTO<?>> T newResourceSysBaseDTO(String user, CloudProvider cloudProvider,
+                                                                      Class<T> resourceClass) {
+        return newResourceBaseDTO(user, cloudProvider, resourceClass);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends ExploratoryCreateDTO<T>> T newExploratoryCreate(ProjectDTO projectDTO, EndpointDTO endpointDTO, Exploratory exploratory,
+                                                                      UserInfo userInfo,
+                                                                      ExploratoryGitCredsDTO exploratoryGitCredsDTO,
+                                                                      Map<String, String> tags) {
+
+        T exploratoryCreate;
+        CloudProvider cloudProvider = endpointDTO.getCloudProvider();
+        switch (cloudProvider) {
+            case AWS:
+                exploratoryCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryCreateAws.class)
+                        .withNotebookInstanceType(exploratory.getShape());
+                break;
+            case AZURE:
+                exploratoryCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryCreateAzure.class)
+                        .withNotebookInstanceSize(exploratory.getShape());
+                if (settingsDAO.isAzureDataLakeEnabled()) {
+                    ((ExploratoryCreateAzure) exploratoryCreate)
+                            .withAzureUserRefreshToken(userInfo.getKeys().get(AZURE_REFRESH_TOKEN_KEY));
+                }
+
+                ((ExploratoryCreateAzure) exploratoryCreate)
+                        .withAzureDataLakeEnabled(Boolean.toString(settingsDAO.isAzureDataLakeEnabled()));
+                break;
+            case GCP:
+                exploratoryCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryCreateGcp.class)
+                        .withNotebookInstanceType(exploratory.getShape());
+                break;
+            default:
+                throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
+        }
+
+        return exploratoryCreate.withExploratoryName(exploratory.getName())
+                .withNotebookImage(exploratory.getDockerImage())
+                .withApplicationName(getApplicationNameFromImage(exploratory.getDockerImage()))
+                .withGitCreds(exploratoryGitCredsDTO.getGitCreds())
+                .withImageName(exploratory.getImageName())
+                .withClusterConfig(exploratory.getClusterConfig())
+                .withProject(exploratory.getProject())
+                .withEndpoint(exploratory.getEndpoint())
+                .withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()))
+                .withTags(tags);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends ExploratoryGitCredsUpdateDTO> T newExploratoryStart(UserInfo userInfo,
+                                                                          UserInstanceDTO userInstance,
+                                                                          EndpointDTO endpointDTO,
+                                                                          ExploratoryGitCredsDTO
+                                                                                  exploratoryGitCredsDTO) {
+        CloudProvider cloudProvider = endpointDTO.getCloudProvider();
+        switch (cloudProvider) {
+            case AWS:
+            case GCP:
+                return (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryGitCredsUpdateDTO.class)
+                        .withNotebookInstanceName(userInstance.getExploratoryId())
+                        .withGitCreds(exploratoryGitCredsDTO.getGitCreds())
+                        .withNotebookImage(userInstance.getImageName())
+                        .withExploratoryName(userInstance.getExploratoryName())
+                        .withReuploadKeyRequired(userInstance.isReuploadKeyRequired())
+                        .withProject(userInstance.getProject())
+                        .withEndpoint(userInstance.getEndpoint());
+            case AZURE:
+                T exploratoryStart = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryActionStartAzure.class)
+                        .withNotebookInstanceName(userInstance.getExploratoryId())
+                        .withGitCreds(exploratoryGitCredsDTO.getGitCreds())
+                        .withNotebookImage(userInstance.getImageName())
+                        .withExploratoryName(userInstance.getExploratoryName())
+                        .withReuploadKeyRequired(userInstance.isReuploadKeyRequired())
+                        .withProject(userInstance.getProject())
+                        .withEndpoint(userInstance.getEndpoint());
+
+                if (settingsDAO.isAzureDataLakeEnabled()) {
+                    ((ExploratoryActionStartAzure) exploratoryStart)
+                            .withAzureUserRefreshToken(userInfo.getKeys().get(AZURE_REFRESH_TOKEN_KEY));
+                }
+
+                ((ExploratoryActionStartAzure) exploratoryStart)
+                        .withAzureDataLakeEnabled(Boolean.toString(settingsDAO.isAzureDataLakeEnabled()));
+
+                return exploratoryStart;
+            default:
+                throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends ExploratoryActionDTO<T>> T newExploratoryStop(String user, UserInstanceDTO userInstance, EndpointDTO endpointDTO) {
+
+        T exploratoryStop;
+        CloudProvider cloudProvider = endpointDTO.getCloudProvider();
+
+        switch (cloudProvider) {
+            case AWS:
+            case GCP:
+                exploratoryStop = (T) newResourceSysBaseDTO(user, cloudProvider, ExploratoryActionDTO.class);
+                break;
+            case AZURE:
+                exploratoryStop = (T) newResourceSysBaseDTO(user, cloudProvider, ExploratoryActionStopAzure.class);
+                break;
+            default:
+                throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
+        }
+
+        return exploratoryStop
+                .withNotebookInstanceName(userInstance.getExploratoryId())
+                .withNotebookImage(userInstance.getImageName())
+                .withExploratoryName(userInstance.getExploratoryName())
+                .withNotebookImage(userInstance.getImageName())
+                .withReuploadKeyRequired(userInstance.isReuploadKeyRequired())
+                .withProject(userInstance.getProject())
+                .withEndpoint(userInstance.getEndpoint());
+    }
+
+    public ExploratoryGitCredsUpdateDTO newGitCredentialsUpdate(UserInfo userInfo, UserInstanceDTO instanceDTO,
+                                                                EndpointDTO endpointDTO,
+                                                                ExploratoryGitCredsDTO exploratoryGitCredsDTO) {
+        checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
+        return newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ExploratoryGitCredsUpdateDTO.class)
+                .withNotebookImage(instanceDTO.getImageName())
+                .withApplicationName(getApplicationNameFromImage(instanceDTO.getImageName()))
+                .withProject(instanceDTO.getProject())
+                .withEndpoint(instanceDTO.getEndpoint())
+                .withNotebookInstanceName(instanceDTO.getExploratoryId())
+                .withExploratoryName(instanceDTO.getExploratoryName())
+                .withGitCreds(exploratoryGitCredsDTO.getGitCreds());
+    }
+
+    public LibraryInstallDTO newLibInstall(UserInfo userInfo, UserInstanceDTO userInstance,
+                                           EndpointDTO endpointDTO, List<LibInstallDTO> libs) {
+        checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
+        return newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), LibraryInstallDTO.class)
+                .withNotebookImage(userInstance.getImageName())
+                .withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
+                .withNotebookInstanceName(userInstance.getExploratoryId())
+                .withExploratoryName(userInstance.getExploratoryName())
+                .withProject(userInstance.getProject())
+                .withEndpoint(endpointDTO.getName())
+                .withLibs(libs);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends LibListExploratoryDTO> T newLibExploratoryList(UserInfo userInfo, UserInstanceDTO userInstance,
+                                                                     EndpointDTO endpointDTO, String group) {
+        checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
+        return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), LibListExploratoryDTO.class)
+                .withNotebookInstanceName(userInstance.getExploratoryId())
+                .withProject(userInstance.getProject())
+                .withEndpoint(endpointDTO.getName())
+                .withNotebookImage(userInstance.getImageName())
+                .withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
+                .withExploratoryName(userInstance.getExploratoryName())
+                .withLibCacheKey(group);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends LibraryInstallDTO> T newLibInstall(UserInfo userInfo, UserInstanceDTO userInstance,
+                                                         UserComputationalResource computationalResource,
+                                                         List<LibInstallDTO> libs, EndpointDTO endpointDTO) {
+        checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
+        return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), LibraryInstallDTO.class)
+                .withComputationalId(computationalResource.getComputationalId())
+                .withComputationalName(computationalResource.getComputationalName())
+                .withExploratoryName(userInstance.getExploratoryName())
+                .withProject(userInstance.getProject())
+                .withEndpoint(endpointDTO.getName())
+                .withComputationalImage(computationalResource.getImageName())
+                .withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
+                .withLibs(libs);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends LibListComputationalDTO> T newLibComputationalList(UserInfo userInfo,
+                                                                         UserInstanceDTO userInstance,
+                                                                         UserComputationalResource
+                                                                                 computationalResource,
+                                                                         EndpointDTO endpointDTO, String group) {
+
+        checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
+        return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), LibListComputationalDTO.class)
+                .withComputationalId(computationalResource.getComputationalId())
+                .withProject(userInstance.getProject())
+                .withEndpoint(endpointDTO.getName())
+                .withComputationalImage(computationalResource.getImageName())
+                .withLibCacheKey(group)
+                .withApplicationName(getApplicationNameFromImage(userInstance.getImageName()));
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends ComputationalBase<T>> T newComputationalCreate(UserInfo userInfo, ProjectDTO projectDTO,
+                                                                     UserInstanceDTO userInstance,
+                                                                     ComputationalCreateFormDTO form,
+                                                                     EndpointDTO endpointDTO) {
+        T computationalCreate;
+        CloudProvider cloudProvider = endpointDTO.getCloudProvider();
+        switch (cloudProvider) {
+            case AZURE:
+                throw new UnsupportedOperationException("Creating dataengine service is not supported yet");
+            case AWS:
+                AwsComputationalCreateForm awsForm = (AwsComputationalCreateForm) form;
+                computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ComputationalCreateAws.class)
+                        .withInstanceCount(awsForm.getInstanceCount())
+                        .withMasterInstanceType(awsForm.getMasterInstanceType())
+                        .withSlaveInstanceType(awsForm.getSlaveInstanceType())
+                        .withSlaveInstanceSpot(awsForm.getSlaveInstanceSpot())
+                        .withSlaveInstanceSpotPctPrice(awsForm.getSlaveInstanceSpotPctPrice())
+                        .withVersion(awsForm.getVersion())
+                        .withConfig((awsForm.getConfig()))
+                        .withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
+                break;
+            case GCP:
+                GcpComputationalCreateForm gcpForm = (GcpComputationalCreateForm) form;
+                computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ComputationalCreateGcp.class)
+                        .withMasterInstanceCount(gcpForm.getMasterInstanceCount())
+                        .withSlaveInstanceCount(gcpForm.getSlaveInstanceCount())
+                        .withPreemptibleCount(gcpForm.getPreemptibleCount())
+                        .withMasterInstanceType(gcpForm.getMasterInstanceType())
+                        .withSlaveInstanceType(gcpForm.getSlaveInstanceType())
+                        .withVersion(gcpForm.getVersion())
+                        .withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
+                break;
+
+            default:
+                throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
+        }
+
+        return computationalCreate
+                .withExploratoryName(form.getNotebookName())
+                .withComputationalName(form.getName())
+                .withNotebookTemplateName(userInstance.getTemplateName())
+                .withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
+                .withNotebookInstanceName(userInstance.getExploratoryId())
+                .withProject(userInstance.getProject())
+                .withTags(userInstance.getTags())
+                .withEndpoint(userInstance.getEndpoint());
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends ComputationalBase<T>> T newComputationalCreate(UserInfo userInfo, ProjectDTO projectDTO,
+                                                                     UserInstanceDTO userInstance,
+                                                                     SparkStandaloneClusterCreateForm form,
+                                                                     EndpointDTO endpointDTO) {
+
+        T computationalCreate;
+        CloudProvider cloudProvider = endpointDTO.getCloudProvider();
+        switch (cloudProvider) {
+            case AWS:
+                computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, SparkComputationalCreateAws.class)
+                        .withDataEngineInstanceCount(form.getDataEngineInstanceCount())
+                        .withDataEngineMasterShape(form.getDataEngineInstanceShape())
+                        .withDataEngineSlaveShape(form.getDataEngineInstanceShape())
+                        .withConfig(form.getConfig())
+                        .withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
+                break;
+            case AZURE:
+                computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, SparkComputationalCreateAzure.class)
+                        .withDataEngineInstanceCount(form.getDataEngineInstanceCount())
+                        .withDataEngineMasterSize(form.getDataEngineInstanceShape())
+                        .withDataEngineSlaveSize(form.getDataEngineInstanceShape())
+                        .withConfig(form.getConfig())
+                        .withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
+                if (settingsDAO.isAzureDataLakeEnabled()) {
+                    ((SparkComputationalCreateAzure) computationalCreate)
+                            .withAzureUserRefreshToken(userInfo.getKeys().get(AZURE_REFRESH_TOKEN_KEY));
+                }
+
+                ((SparkComputationalCreateAzure) computationalCreate)
+                        .withAzureDataLakeEnabled(Boolean.toString(settingsDAO.isAzureDataLakeEnabled()));
+
+                break;
+            case GCP:
+                computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, SparkComputationalCreateGcp.class)
+                        .withDataEngineInstanceCount(form.getDataEngineInstanceCount())
+                        .withDataEngineMasterSize(form.getDataEngineInstanceShape())
+                        .withDataEngineSlaveSize(form.getDataEngineInstanceShape())
+                        .withConfig(form.getConfig())
+                        .withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
+                break;
+            default:
+                throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
+        }
+
+        return computationalCreate
+                .withExploratoryName(form.getNotebookName())
+                .withComputationalName(form.getName())
+                .withNotebookTemplateName(userInstance.getTemplateName())
+                .withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
+                .withNotebookInstanceName(userInstance.getExploratoryId())
+                .withProject(userInstance.getProject())
+                .withTags(userInstance.getTags())
+                .withEndpoint(userInstance.getEndpoint());
+    }
+
+    @SuppressWarnings("unchecked")
+    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())
+                .withComputationalName(computationalResource.getComputationalName())
+                .withNotebookInstanceName(userInstanceDTO.getExploratoryId())
+                .withProject(userInstanceDTO.getProject())
+                .withEndpoint(userInstanceDTO.getEndpoint());
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends ComputationalBase<T>> T newComputationalStop(String resourceCreator, UserInstanceDTO exploratory,
+                                                                   String computationalName, EndpointDTO endpointDTO) {
+        return (T) newResourceSysBaseDTO(resourceCreator, endpointDTO.getCloudProvider(), ComputationalStopDTO.class)
+                .withExploratoryName(exploratory.getExploratoryName())
+                .withComputationalName(computationalName)
+                .withNotebookInstanceName(exploratory.getExploratoryId())
+                .withApplicationName(getApplicationNameFromImage(exploratory.getImageName()))
+                .withProject(exploratory.getProject())
+                .withEndpoint(endpointDTO.getName());
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends ComputationalBase<T>> T newComputationalStart(UserInfo userInfo, UserInstanceDTO exploratory,
+                                                                    String computationalName, EndpointDTO endpointDTO) {
+        return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ComputationalStartDTO.class)
+                .withExploratoryName(exploratory.getExploratoryName())
+                .withComputationalName(computationalName)
+                .withNotebookInstanceName(exploratory.getExploratoryId())
+                .withApplicationName(getApplicationNameFromImage(exploratory.getImageName()))
+                .withProject(exploratory.getProject())
+                .withEndpoint(endpointDTO.getName());
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends ExploratoryImageDTO> T newExploratoryImageCreate(UserInfo userInfo, UserInstanceDTO userInstance,
+                                                                       String imageName, EndpointDTO endpointDTO, ProjectDTO projectDTO) {
+        checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
+        return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ExploratoryImageDTO.class)
+                .withProject(userInstance.getProject())
+                .withNotebookInstanceName(userInstance.getExploratoryId())
+                .withExploratoryName(userInstance.getExploratoryName())
+                .withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
+                .withNotebookImage(userInstance.getImageName())
+                .withImageName(imageName)
+                .withEndpoint(userInstance.getEndpoint())
+                .withTags(userInstance.getTags())
+                .withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends ComputationalBase<T>> T newComputationalCheckInactivity(UserInfo userInfo,
+                                                                              UserInstanceDTO exploratory,
+                                                                              UserComputationalResource cr, EndpointDTO endpointDTO) {
+        return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ComputationalCheckInactivityDTO.class)
+                .withExploratoryName(exploratory.getExploratoryName())
+                .withComputationalName(cr.getComputationalName())
+                .withNotebookInstanceName(exploratory.getExploratoryId())
+                .withApplicationName(getApplicationNameFromImage(exploratory.getImageName()))
+                .withNotebookImageName(exploratory.getImageName())
+                .withImage(cr.getImageName())
+                .withComputationalId(cr.getComputationalId())
+                .withProject(exploratory.getProject())
+                .withEndpoint(endpointDTO.getName());
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public <T extends EnvBackupDTO> T newBackupCreate(BackupFormDTO backupFormDTO, String id) {
+
+        return (T) EnvBackupDTO.builder()
+                .configFiles(backupFormDTO.getConfigFiles())
+                .certificates(backupFormDTO.getCertificates())
+                .keys(backupFormDTO.getKeys())
+                .jars(backupFormDTO.getJars())
+                .databaseBackup(backupFormDTO.isDatabaseBackup())
+                .logsBackup(backupFormDTO.isLogsBackup())
+                .id(id)
+                .build();
+    }
+
+    public ComputationalClusterConfigDTO newClusterConfigUpdate(UserInfo userInfo, UserInstanceDTO userInstanceDTO,
+                                                                UserComputationalResource compRes,
+                                                                List<ClusterConfig> config, EndpointDTO endpointDTO) {
+        CloudProvider cloudProvider = endpointDTO.getCloudProvider();
+        final ComputationalClusterConfigDTO clusterConfigDTO = newResourceSysBaseDTO(userInfo.getName(), cloudProvider,
+                ComputationalClusterConfigDTO.class)
+                .withExploratoryName(userInstanceDTO.getExploratoryName())
+                .withNotebookInstanceName(userInstanceDTO.getExploratoryId())
+                .withComputationalName(compRes.getComputationalName())
+                .withApplicationName(compRes.getImageName())
+                .withProject(userInstanceDTO.getProject())
+                .withEndpoint(userInstanceDTO.getEndpoint());
+        clusterConfigDTO.setCopmutationalId(compRes.getComputationalId());
+        clusterConfigDTO.setConfig(config);
+        if (cloudProvider == AZURE && settingsDAO.isAzureDataLakeEnabled()) {
+            clusterConfigDTO.setAzureUserRefreshToken(userInfo.getKeys().get(AZURE_REFRESH_TOKEN_KEY));
+        }
+
+        return clusterConfigDTO;
+    }
+
+    public ExploratoryReconfigureSparkClusterActionDTO newClusterConfigUpdate(UserInfo userInfo,
+                                                                              UserInstanceDTO userInstance,
+                                                                              List<ClusterConfig> config,
+                                                                              EndpointDTO endpointDTO) {
+
+        CloudProvider cloudProvider = endpointDTO.getCloudProvider();
+        final ExploratoryReconfigureSparkClusterActionDTO dto =
+                newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryReconfigureSparkClusterActionDTO.class)
+                        .withNotebookInstanceName(userInstance.getExploratoryId())
+                        .withExploratoryName(userInstance.getExploratoryName())
+                        .withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
+                        .withNotebookImage(userInstance.getImageName())
+                        .withConfig(config)
+                        .withProject(userInstance.getProject())
+                        .withEndpoint(userInstance.getEndpoint());
+        if (cloudProvider == AZURE && settingsDAO.isAzureDataLakeEnabled()) {
+            dto.withAzureUserRefreshToken(userInfo.getKeys().get(AZURE_REFRESH_TOKEN_KEY));
+        }
+
+        return dto;
+    }
+
+    public ExploratoryCheckInactivityAction newExploratoryCheckInactivityAction(UserInfo userInfo,
+                                                                                UserInstanceDTO userInstance,
+                                                                                EndpointDTO endpointDTO) {
+        final ExploratoryCheckInactivityAction dto = newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(),
+                ExploratoryCheckInactivityAction.class);
+        dto.withNotebookInstanceName(userInstance.getExploratoryId())
+                .withNotebookImage(userInstance.getImageName())
+                .withExploratoryName(userInstance.getExploratoryName())
+                .withReuploadKeyRequired(userInstance.isReuploadKeyRequired())
+                .withProject(userInstance.getProject())
+                .withEndpoint(endpointDTO.getName());
+        return dto;
+    }
+
+    public ProjectCreateDTO newProjectCreate(UserInfo userInfo, ProjectDTO projectDTO, EndpointDTO endpointDTO) {
+        return ProjectCreateDTO.builder()
+                .key(projectDTO.getKey().replace("\n", ""))
+                .name(projectDTO.getName())
+                .tag(projectDTO.getTag())
+                .endpoint(endpointDTO.getName())
+                .build()
+                .withCloudSettings(cloudSettings(userInfo.getName(), endpointDTO.getCloudProvider()));
+    }
+
+    public ProjectActionDTO newProjectAction(UserInfo userInfo, String project, EndpointDTO endpointDTO) {
+        return new ProjectActionDTO(project, endpointDTO.getName())
+                .withCloudSettings(cloudSettings(userInfo.getName(), endpointDTO.getCloudProvider()));
+    }
+
+    /**
+     * Returns application name basing on docker image
+     *
+     * @param imageName docker image name
+     * @return application name
+     */
+    private String getApplicationNameFromImage(String imageName) {
+        if (imageName != null) {
+            int pos = imageName.indexOf('-');
+            if (pos > 0) {
+                return imageName.substring(pos + 1);
+            }
+        }
+        return "";
+    }
+
+    private void checkInappropriateCloudProviderOrElseThrowException(CloudProvider provider) {
+        if (provider != AWS && provider != AZURE && provider != GCP) {
+            throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + provider);
+        }
+    }
+}
+
+
+
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/validation/MavenLibraryNameValidator.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/validation/MavenLibraryNameValidator.java
new file mode 100644
index 0000000..ea92af5
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/validation/MavenLibraryNameValidator.java
@@ -0,0 +1,41 @@
+/*
+ * 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.datalab.backendapi.validation;
+
+import com.epam.datalab.backendapi.validation.annotation.LibNameValid;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+@Slf4j
+public class MavenLibraryNameValidator implements ConstraintValidator<LibNameValid, String> {
+    @Override
+    public void initialize(LibNameValid libNameValid) {
+        log.trace("MavenLibraryNameValidator initialized");
+    }
+
+    @Override
+    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
+        return StringUtils.isNotEmpty(s) && s.split(":").length == 3;
+
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/validation/SchedulerJobDTOValidator.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/validation/SchedulerJobDTOValidator.java
new file mode 100644
index 0000000..4b32621
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/validation/SchedulerJobDTOValidator.java
@@ -0,0 +1,47 @@
+/*
+ * 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.datalab.backendapi.validation;
+
+import com.epam.datalab.backendapi.validation.annotation.SchedulerJobDTOValid;
+import com.epam.datalab.dto.SchedulerJobDTO;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.util.Objects;
+
+public class SchedulerJobDTOValidator implements ConstraintValidator<SchedulerJobDTOValid, SchedulerJobDTO> {
+    @Override
+    public void initialize(SchedulerJobDTOValid schedulerJobDTOValid) {
+        //do nothing
+    }
+
+    @Override
+    public boolean isValid(SchedulerJobDTO schedulerJobDTO, ConstraintValidatorContext constraintValidatorContext) {
+        if (!schedulerJobDTO.isCheckInactivityRequired() && Objects.isNull(schedulerJobDTO.getTerminateDateTime())) {
+            return !schedulerJobDTO.getStartDaysRepeat().isEmpty() || !schedulerJobDTO.getStopDaysRepeat().isEmpty();
+        } else if (schedulerJobDTO.isCheckInactivityRequired() && Objects.isNull(schedulerJobDTO.getMaxInactivity())) {
+            constraintValidatorContext.disableDefaultConstraintViolation();
+            constraintValidatorContext.buildConstraintViolationWithTemplate("Max inactivity time should be set").addConstraintViolation();
+            return false;
+        } else {
+            return true;
+        }
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/validation/annotation/LibNameValid.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/validation/annotation/LibNameValid.java
new file mode 100644
index 0000000..22ab4f4
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/validation/annotation/LibNameValid.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.backendapi.validation.annotation;
+
+import com.epam.datalab.backendapi.validation.MavenLibraryNameValidator;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Constraint(validatedBy = {MavenLibraryNameValidator.class})
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(value = RetentionPolicy.RUNTIME)
+public @interface LibNameValid {
+
+
+    String message() default "Wrong library name format. Should be <groupId>:<artifactId>:<versionId>";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/validation/annotation/SchedulerJobDTOValid.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/validation/annotation/SchedulerJobDTOValid.java
new file mode 100644
index 0000000..72f766e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/validation/annotation/SchedulerJobDTOValid.java
@@ -0,0 +1,42 @@
+/*
+ * 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.datalab.backendapi.validation.annotation;
+
+import com.epam.datalab.backendapi.validation.SchedulerJobDTOValidator;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Constraint(validatedBy = {SchedulerJobDTOValidator.class})
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+@Retention(value = RetentionPolicy.RUNTIME)
+public @interface SchedulerJobDTOValid {
+
+
+    String message() default "Start/stop days or termination date is required for scheduler";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}
\ No newline at end of file
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
deleted file mode 100644
index beaf917..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * 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;
-
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.IndexCreator;
-import com.epam.dlab.backendapi.domain.ExploratoryLibCache;
-import com.epam.dlab.backendapi.dropwizard.bundles.DlabKeycloakBundle;
-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.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;
-import com.epam.dlab.cloud.CloudModule;
-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.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;
-import com.google.inject.Key;
-import com.google.inject.name.Names;
-import de.thomaskrille.dropwizard_template_config.TemplateConfigBundle;
-import de.thomaskrille.dropwizard_template_config.TemplateConfigBundleConfiguration;
-import io.dropwizard.Application;
-import io.dropwizard.assets.AssetsBundle;
-import io.dropwizard.forms.MultiPartBundle;
-import io.dropwizard.jersey.setup.JerseyEnvironment;
-import io.dropwizard.jetty.BiDiGzipHandler;
-import io.dropwizard.setup.Bootstrap;
-import io.dropwizard.setup.Environment;
-import lombok.extern.slf4j.Slf4j;
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.HandlerWrapper;
-
-/**
- * Self Service based on Dropwizard application.
- */
-@Slf4j
-public class SelfServiceApplication extends Application<SelfServiceApplicationConfiguration> {
-	public static final String GUACAMOLE_SERVLET_PATH = "/api/tunnel";
-	private static Injector appInjector;
-
-	public static Injector getInjector() {
-		return appInjector;
-	}
-
-	public static void setInjector(Injector injector) {
-		SelfServiceApplication.appInjector = injector;
-	}
-
-	public static void main(String... args) throws Exception {
-		if (ServiceUtils.printAppVersion(SelfServiceApplication.class, args)) {
-			return;
-		}
-		new SelfServiceApplication().run(args);
-	}
-
-	@Override
-	public void initialize(Bootstrap<SelfServiceApplicationConfiguration> bootstrap) {
-		super.initialize(bootstrap);
-		bootstrap.addBundle(new MultiPartBundle());
-		bootstrap.addBundle(new AssetsBundle("/webapp/dist", "/", "index.html"));
-		bootstrap.addBundle(new TemplateConfigBundle(
-				new TemplateConfigBundleConfiguration().fileIncludePath(ServiceUtils.getConfPath())
-		));
-
-		bootstrap.addBundle(new DlabKeycloakBundle());
-	}
-
-	@Override
-	public void run(SelfServiceApplicationConfiguration configuration, Environment environment) {
-
-		CloudModule cloudModule = ModuleFactory.getCloudProviderModule(configuration);
-		Injector injector = Guice.createInjector(ModuleFactory.getModule(configuration, environment), cloudModule);
-		setInjector(injector);
-
-		cloudModule.init(environment, injector);
-		if (configuration.isMongoMigrationEnabled()) {
-			environment.lifecycle().addServerLifecycleListener(server -> applyMongoMigration(configuration));
-		}
-		environment.lifecycle().addServerLifecycleListener(injector.getInstance(MongoStartupListener.class));
-		final RestoreHandlerStartupListener restoreHandlerStartupListener =
-				new RestoreHandlerStartupListener(injector.getInstance(Key.get(RESTService.class,
-						Names.named(ServiceConsts.PROVISIONING_SERVICE_NAME))), injector.getInstance(EndpointService.class));
-		environment.lifecycle().addServerLifecycleListener(restoreHandlerStartupListener);
-		environment.lifecycle().addServerLifecycleListener(this::disableGzipHandlerForGuacamoleServlet);
-		environment.lifecycle().manage(injector.getInstance(IndexCreator.class));
-		environment.lifecycle().manage(injector.getInstance(ExploratoryLibCache.class));
-		environment.lifecycle().manage(injector.getInstance(ManagedScheduler.class));
-		environment.healthChecks().register(ServiceConsts.MONGO_NAME, injector.getInstance(MongoHealthCheck.class));
-
-		environment.servlets().addServlet("GuacamoleServlet", injector.getInstance(GuacamoleServlet.class))
-				.addMapping(GUACAMOLE_SERVLET_PATH);
-
-
-		JerseyEnvironment jersey = environment.jersey();
-
-		jersey.register(new RuntimeExceptionMapper());
-		jersey.register(new JsonProcessingExceptionMapper());
-		jersey.register(new ResourceConflictExceptionMapper());
-		jersey.register(new ResourceNotFoundExceptionMapper());
-		jersey.register(new DlabValidationExceptionMapper());
-		jersey.register(new ValidationExceptionMapper());
-		jersey.register(new ResourceQuoteReachedExceptionMapper());
-
-		jersey.register(injector.getInstance(InfrastructureTemplateResource.class));
-		jersey.register(injector.getInstance(InfrastructureInfoResource.class));
-
-		jersey.register(injector.getInstance(EnvironmentStatusCallback.class));
-
-		jersey.register(injector.getInstance(ComputationalCallback.class));
-
-		jersey.register(injector.getInstance(UserSettingsResource.class));
-
-		jersey.register(injector.getInstance(ExploratoryResource.class));
-		jersey.register(injector.getInstance(ExploratoryCallback.class));
-
-		jersey.register(injector.getInstance(LibExploratoryResource.class));
-		jersey.register(injector.getInstance(LibraryCallback.class));
-
-		jersey.register(injector.getInstance(GitCredsResource.class));
-		jersey.register(injector.getInstance(GitCredsCallback.class));
-		jersey.register(injector.getInstance(SchedulerJobResource.class));
-		jersey.register(injector.getInstance(ImageExploratoryResource.class));
-		jersey.register(injector.getInstance(ImageCallback.class));
-		jersey.register(injector.getInstance(BackupResource.class));
-		jersey.register(injector.getInstance(BackupCallback.class));
-		jersey.register(injector.getInstance(EnvironmentResource.class));
-		jersey.register(injector.getInstance(ReuploadKeyCallback.class));
-		jersey.register(injector.getInstance(CheckInactivityCallback.class));
-		jersey.register(injector.getInstance(SystemInfoResource.class));
-		jersey.register(injector.getInstance(UserGroupResource.class));
-		jersey.register(injector.getInstance(UserRoleResource.class));
-		jersey.register(injector.getInstance(ApplicationSettingResource.class));
-		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));
-	}
-
-	private void disableGzipHandlerForGuacamoleServlet(Server server) {
-		Handler handler = server.getHandler();
-		while (handler instanceof HandlerWrapper) {
-			handler = ((HandlerWrapper) handler).getHandler();
-			if (handler instanceof BiDiGzipHandler) {
-				log.debug("Disabling Gzip handler for guacamole servlet");
-				((BiDiGzipHandler) handler).setExcludedPaths(GUACAMOLE_SERVLET_PATH);
-			}
-		}
-	}
-
-	private void applyMongoMigration(SelfServiceApplicationConfiguration configuration) {
-		final MongoServiceFactory mongoFactory = configuration.getMongoFactory();
-
-		new DlabMongoMigration(mongoFactory.getHost(), mongoFactory.getPort(), mongoFactory.getUsername(),
-				mongoFactory.getPassword(), mongoFactory.getDatabase()).migrate();
-	}
-
-}
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
deleted file mode 100644
index 946fabc..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Audit.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 com.epam.dlab.backendapi.domain.AuditResourceTypeEnum;
-
-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();
-
-    AuditResourceTypeEnum type();
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/BudgetLimited.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/BudgetLimited.java
deleted file mode 100644
index 1d58792..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/BudgetLimited.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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;
-
-/**
- * Annotation used to disallow execution of method that is annotated by this annotation in case when
- * budget limit in reached. Budget can be specified in self service configuration
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface BudgetLimited {
-}
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
deleted file mode 100644
index 44ca32b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Info.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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/Project.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Project.java
deleted file mode 100644
index 0ce3414..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Project.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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 Project {
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/ProjectAdmin.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/ProjectAdmin.java
deleted file mode 100644
index 2fca3cd..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/ProjectAdmin.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface ProjectAdmin {
-}
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
deleted file mode 100644
index 100df0d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/ResourceName.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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/annotation/User.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/User.java
deleted file mode 100644
index b56dd20..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/User.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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 User {
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/KeycloakAuthenticator.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/KeycloakAuthenticator.java
deleted file mode 100644
index 4b39290..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/KeycloakAuthenticator.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.auth;
-
-import com.epam.dlab.auth.UserInfo;
-import de.ahus1.keycloak.dropwizard.AbstractKeycloakAuthenticator;
-import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
-import org.keycloak.KeycloakSecurityContext;
-import org.keycloak.representations.AccessToken;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.List;
-
-import static java.util.Collections.emptyList;
-
-public class KeycloakAuthenticator extends AbstractKeycloakAuthenticator<UserInfo> {
-
-	private static final String GROUPS_CLAIM = "groups";
-
-	public KeycloakAuthenticator(KeycloakConfiguration keycloakConfiguration) {
-		super(keycloakConfiguration);
-	}
-
-	@Override
-	@SuppressWarnings("unchecked")
-	protected UserInfo prepareAuthentication(KeycloakSecurityContext keycloakSecurityContext,
-	                                         HttpServletRequest httpServletRequest,
-	                                         KeycloakConfiguration keycloakConfiguration) {
-		final AccessToken token = keycloakSecurityContext.getToken();
-		final UserInfo userInfo = new UserInfo(token.getPreferredUsername(),
-				keycloakSecurityContext.getTokenString());
-		userInfo.addRoles((List<String>) token.getOtherClaims().getOrDefault(GROUPS_CLAIM, emptyList()));
-		return userInfo;
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/SelfServiceSecurityAuthorizer.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/SelfServiceSecurityAuthorizer.java
deleted file mode 100644
index 2d93b74..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/SelfServiceSecurityAuthorizer.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.auth;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.roles.RoleType;
-import com.epam.dlab.backendapi.roles.UserRoles;
-import com.google.inject.Singleton;
-import io.dropwizard.auth.Authorizer;
-
-@Singleton
-public class SelfServiceSecurityAuthorizer implements Authorizer<UserInfo> {
-	@Override
-	public boolean authorize(UserInfo principal, String role) {
-		return UserRoles.checkAccess(principal, RoleType.PAGE, role, principal.getRoles());
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/filters/DropwizardBearerTokenFilterImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/filters/DropwizardBearerTokenFilterImpl.java
deleted file mode 100644
index df6f5fa..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/filters/DropwizardBearerTokenFilterImpl.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.auth.filters;
-
-import org.keycloak.adapters.AdapterDeploymentContext;
-import org.keycloak.adapters.KeycloakDeployment;
-import org.keycloak.adapters.NodesRegistrationManagement;
-import org.keycloak.jaxrs.JaxrsBearerTokenFilterImpl;
-
-import javax.annotation.Priority;
-import javax.ws.rs.Priorities;
-import javax.ws.rs.container.PreMatching;
-
-@PreMatching
-@Priority(Priorities.AUTHENTICATION)
-public class DropwizardBearerTokenFilterImpl extends JaxrsBearerTokenFilterImpl {
-
-	public DropwizardBearerTokenFilterImpl(KeycloakDeployment keycloakDeployment) {
-		deploymentContext = new AdapterDeploymentContext(keycloakDeployment);
-		nodesRegistrationManagement = new NodesRegistrationManagement();
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/conf/CloudConfiguration.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/conf/CloudConfiguration.java
deleted file mode 100644
index 2693e4b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/conf/CloudConfiguration.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.conf;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-@Data
-public class CloudConfiguration {
-
-	private final String os;
-	private final String serviceBaseName;
-	private final String edgeInstanceSize;
-	private final String subnetId;
-	private final String region;
-	private final String zone;
-	private final String confTagResourceId;
-	private final String securityGroupIds;
-	private final String ssnInstanceSize;
-	private final String notebookVpcId;
-	private final String notebookSubnetId;
-	private final String confKeyDir;
-	private final String vpcId;
-	private final String azureResourceGroupName;
-	private final String ssnStorageAccountTagName;
-	private final String sharedStorageAccountTagName;
-	private final String datalakeTagName;
-	private final String azureClientId;
-	private final String peeringId;
-	private final String gcpProjectId;
-	@JsonProperty("ldap")
-	private final LdapConfig ldapConfig;
-
-	@Data
-	public static class LdapConfig {
-		private final String host;
-		private final String dn;
-		private final String ou;
-		private final String user;
-		private final String password;
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/conf/KeycloakConfiguration.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/conf/KeycloakConfiguration.java
deleted file mode 100644
index 212d565..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/conf/KeycloakConfiguration.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.conf;
-
-import lombok.Data;
-
-@Data
-public class KeycloakConfiguration extends de.ahus1.keycloak.dropwizard.KeycloakConfiguration {
-	private String redirectUri;
-}
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
deleted file mode 100644
index 7d0e874..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/conf/SelfServiceApplicationConfiguration.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * 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.conf;
-
-import com.epam.dlab.ServiceConfiguration;
-import com.epam.dlab.backendapi.domain.SchedulerConfigurationData;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.rest.client.RESTServiceFactory;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.dropwizard.client.JerseyClientConfiguration;
-import io.dropwizard.util.Duration;
-import org.hibernate.validator.constraints.NotEmpty;
-
-import javax.validation.Valid;
-import javax.validation.constraints.Max;
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotNull;
-import java.util.Map;
-
-/**
- * Configuration for Self Service.
- */
-public class SelfServiceApplicationConfiguration extends ServiceConfiguration {
-
-	@Min(value = 2)
-	@JsonProperty
-	private int minEmrInstanceCount;
-
-	@Max(value = 1000)
-	@JsonProperty
-	private int maxEmrInstanceCount;
-
-	@Min(value = 10)
-	@JsonProperty
-	private int minEmrSpotInstanceBidPct;
-
-	@Max(value = 95)
-	@JsonProperty
-	private int maxEmrSpotInstanceBidPct;
-
-	@Min(value = 2)
-	@JsonProperty
-	private int minSparkInstanceCount;
-
-	@Max(value = 1000)
-	@JsonProperty
-	private int maxSparkInstanceCount;
-
-	@JsonProperty
-	private String ssnInstanceSize;
-
-	@JsonProperty
-	private boolean rolePolicyEnabled = false;
-
-	@JsonProperty
-	private boolean roleDefaultAccess = false;
-
-	@JsonProperty
-	private Duration checkEnvStatusTimeout = Duration.minutes(10);
-
-	@JsonProperty
-	private boolean billingSchedulerEnabled = false;
-
-	@JsonProperty
-	private boolean auditEnabled = false;
-
-	@NotEmpty
-	@JsonProperty
-	private String billingConfFile;
-	@JsonProperty
-	private int minInstanceCount;
-	@JsonProperty
-	private int maxInstanceCount;
-	@JsonProperty
-	private int minDataprocPreemptibleCount;
-	@JsonProperty
-	private int maxUserNameLength;
-	@JsonProperty
-	private boolean gcpOuauth2AuthenticationEnabled;
-	@JsonProperty
-	private boolean mongoMigrationEnabled;
-	@JsonProperty
-	private int privateKeySize = 2048;
-	@Valid
-	@NotNull
-	private Map<String, SchedulerConfigurationData> schedulers;
-
-
-	@Valid
-	@NotNull
-	@JsonProperty("jerseyClient")
-	private JerseyClientConfiguration jerseyClient = new JerseyClientConfiguration();
-
-	@Valid
-	@NotNull
-	@JsonProperty(ServiceConsts.MAVEN_SEARCH_API)
-	private RESTServiceFactory mavenApiFactory;
-
-	@Valid
-	@NotNull
-	private Map<String, String> guacamole;
-
-	private String serviceBaseName;
-	private String os;
-
-	private KeycloakConfiguration keycloakConfiguration = new KeycloakConfiguration();
-
-	public Map<String, String> getGuacamole() {
-		return guacamole;
-	}
-
-	public String getGuacamoleHost() {
-		return guacamole.get("serverHost");
-	}
-
-	public Integer getGuacamolePort() {
-		return Integer.valueOf(guacamole.get("serverPort"));
-	}
-
-	public JerseyClientConfiguration getJerseyClientConfiguration() {
-		return jerseyClient;
-	}
-
-	public Map<String, SchedulerConfigurationData> getSchedulers() {
-		return schedulers;
-	}
-
-	public boolean isGcpOuauth2AuthenticationEnabled() {
-		return gcpOuauth2AuthenticationEnabled;
-	}
-
-	/**
-	 * Returns the minimum number of slave EMR instances than could be created.
-	 */
-	public int getMinEmrInstanceCount() {
-		return minEmrInstanceCount;
-	}
-
-	/**
-	 * Returns the maximum number of slave EMR instances than could be created.
-	 */
-	public int getMaxEmrInstanceCount() {
-		return maxEmrInstanceCount;
-	}
-
-	/**
-	 * Returns the timeout for check the status of environment via provisioning service.
-	 */
-	public Duration getCheckEnvStatusTimeout() {
-		return checkEnvStatusTimeout;
-	}
-
-	public int getMinEmrSpotInstanceBidPct() {
-		return minEmrSpotInstanceBidPct;
-	}
-
-	public int getMaxEmrSpotInstanceBidPct() {
-		return maxEmrSpotInstanceBidPct;
-	}
-
-	public int getMinSparkInstanceCount() {
-		return minSparkInstanceCount;
-	}
-
-	public int getMaxSparkInstanceCount() {
-		return maxSparkInstanceCount;
-	}
-
-	/**
-	 * Return the <b>true</b> if using roles policy to DLab features.
-	 */
-	public boolean isRolePolicyEnabled() {
-		return rolePolicyEnabled;
-	}
-
-	/**
-	 * Return the default access to DLab features using roles policy.
-	 */
-	public boolean getRoleDefaultAccess() {
-		return roleDefaultAccess;
-	}
-
-
-	/**
-	 * Return the <b>true</b> if the billing scheduler is enabled.
-	 */
-	public boolean isBillingSchedulerEnabled() {
-		return billingSchedulerEnabled;
-	}
-
-	public boolean isAuditEnabled() {
-		return auditEnabled;
-	}
-
-	/**
-	 * Return the default access to DLab features using roles policy.
-	 */
-	public String getBillingConfFile() {
-		return billingConfFile;
-	}
-
-
-	public int getMinInstanceCount() {
-		return minInstanceCount;
-	}
-
-	public int getMaxInstanceCount() {
-		return maxInstanceCount;
-	}
-
-	public int getMinDataprocPreemptibleCount() {
-		return minDataprocPreemptibleCount;
-	}
-
-	public int getMaxUserNameLength() {
-		return maxUserNameLength;
-	}
-
-	public int getPrivateKeySize() {
-		return privateKeySize;
-	}
-
-	public String getSsnInstanceSize() {
-		return ssnInstanceSize;
-	}
-
-	public boolean isMongoMigrationEnabled() {
-		return mongoMigrationEnabled;
-	}
-
-	@NotNull
-	public RESTServiceFactory getMavenApiFactory() {
-		return mavenApiFactory;
-	}
-
-	public KeycloakConfiguration getKeycloakConfiguration() {
-		return keycloakConfiguration;
-	}
-
-	public String getServiceBaseName() {
-		return serviceBaseName;
-	}
-
-	public String getOs() {
-		return os;
-	}
-}
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
deleted file mode 100644
index cd7b086..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.AuditDTO;
-import com.epam.dlab.backendapi.domain.AuditPaginationDTO;
-
-import java.util.List;
-
-public interface AuditDAO {
-    void save(AuditDTO audit);
-
-    List<AuditPaginationDTO> getAudit(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd, int pageNumber, int pageSize);
-}
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
deleted file mode 100644
index a1db015..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * 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.AuditDTO;
-import com.epam.dlab.backendapi.domain.AuditPaginationDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.mongodb.client.model.Facet;
-import com.mongodb.client.model.Filters;
-import com.mongodb.client.model.Sorts;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.time.Instant;
-import java.time.ZoneOffset;
-import java.time.temporal.ChronoUnit;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
-import java.util.TimeZone;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
-
-import static com.epam.dlab.backendapi.dao.ComputationalDAO.PROJECT;
-import static com.mongodb.client.model.Aggregates.count;
-import static com.mongodb.client.model.Aggregates.facet;
-import static com.mongodb.client.model.Aggregates.group;
-import static com.mongodb.client.model.Aggregates.limit;
-import static com.mongodb.client.model.Aggregates.match;
-import static com.mongodb.client.model.Aggregates.skip;
-import static com.mongodb.client.model.Aggregates.sort;
-import static com.mongodb.client.model.Filters.gte;
-import static com.mongodb.client.model.Filters.in;
-import static com.mongodb.client.model.Filters.lte;
-
-public class AuditDAOImpl extends BaseDAO implements AuditDAO {
-    private static final String AUDIT_COLLECTION = "audit";
-    private static final String RESOURCE_NAME_FIELD = "resourceName";
-    private static final String RESOURCE_TYPE_FIELD = "type";
-    private static final String TIMESTAMP_FIELD = "timestamp";
-    private static final String COUNT_FIELD = "count";
-    private static final String AUDIT_FACET = "auditFacet";
-    private static final String TOTAL_COUNT_FACET = "totalCountFacet";
-    private static final String RESOURCE_NAME_FACET = "resourceNameFacet";
-    private static final String USER_FACET = "userFacet";
-    private static final String PROJECT_FACET = "projectFacet";
-    private static final String RESOURCE_TYPE_FACET = "typeFacet";
-
-    @Override
-    public void save(AuditDTO audit) {
-        insertOne(AUDIT_COLLECTION, audit);
-    }
-
-    @Override
-    public List<AuditPaginationDTO> getAudit(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd,
-                                             int pageNumber, int pageSize) {
-        List<Bson> valuesPipeline = new ArrayList<>();
-        List<Bson> countPipeline = new ArrayList<>();
-        List<Bson> matchCriteria = matchCriteria(users, projects, resourceNames, resourceTypes, dateStart, dateEnd);
-        if (!matchCriteria.isEmpty()) {
-            Bson match = match(Filters.and(matchCriteria));
-            valuesPipeline.add(match);
-            countPipeline.add(match);
-        }
-        countPipeline.add(count());
-        valuesPipeline.add(sortCriteria());
-        valuesPipeline.addAll(Arrays.asList(skip(pageSize * (pageNumber - 1)), limit(pageSize)));
-
-        List<Bson> userFilter = Collections.singletonList(group(getGroupingFields(USER)));
-        List<Bson> projectFilter = Collections.singletonList(group(getGroupingFields(PROJECT)));
-        List<Bson> resourceNameFilter = Collections.singletonList(group(getGroupingFields(RESOURCE_NAME_FIELD)));
-        List<Bson> resourceTypeFilter = Collections.singletonList(group(getGroupingFields(RESOURCE_TYPE_FIELD)));
-
-        List<Bson> facets = Collections.singletonList(facet(new Facet(AUDIT_FACET, valuesPipeline), new Facet(TOTAL_COUNT_FACET, countPipeline),
-                new Facet(RESOURCE_NAME_FACET, resourceNameFilter), new Facet(USER_FACET, userFilter), new Facet(PROJECT_FACET, projectFilter),
-                new Facet(RESOURCE_TYPE_FACET, resourceTypeFilter)));
-        return StreamSupport.stream(aggregate(AUDIT_COLLECTION, facets).spliterator(), false)
-                .map(this::toAuditPaginationDTO)
-                .collect(Collectors.toList());
-    }
-
-    private List<Bson> matchCriteria(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd) {
-        List<Bson> searchCriteria = new ArrayList<>();
-        inCriteria(searchCriteria, users, USER);
-        inCriteria(searchCriteria, projects, PROJECT);
-        inCriteria(searchCriteria, resourceNames, RESOURCE_NAME_FIELD);
-        inCriteria(searchCriteria, resourceTypes, RESOURCE_TYPE_FIELD);
-        if (StringUtils.isNotEmpty(dateStart)) {
-            Instant from = getInstant(dateStart);
-            Date date = new Date(from.toEpochMilli());
-            searchCriteria.add(gte(TIMESTAMP_FIELD, date));
-        }
-        if (StringUtils.isNotEmpty(dateEnd)) {
-            Instant to = getInstant(dateEnd).plus(1, ChronoUnit.DAYS);
-            Date date = new Date(to.toEpochMilli());
-            searchCriteria.add(lte(TIMESTAMP_FIELD, date));
-        }
-        return searchCriteria;
-    }
-
-    private Bson sortCriteria() {
-        return sort(Sorts.descending(TIMESTAMP_FIELD));
-    }
-
-    private AuditPaginationDTO toAuditPaginationDTO(Document document) {
-        List<Document> countDocuments = (List<Document>) document.get(TOTAL_COUNT_FACET);
-        final int count = countDocuments.isEmpty() ? 0 : countDocuments.get(0).getInteger(COUNT_FIELD);
-        Set<String> userFilter = getFilter(document, USER_FACET, USER);
-        Set<String> projectFilter = getFilter(document, PROJECT_FACET, PROJECT);
-        Set<String> resourceNameFilter = getFilter(document, RESOURCE_NAME_FACET, RESOURCE_NAME_FIELD);
-        Set<String> resourceTypeFilter = getFilter(document, RESOURCE_TYPE_FACET, RESOURCE_TYPE_FIELD);
-        List<AuditDTO> auditDTOs = (List<AuditDTO>) document.get(AUDIT_FACET);
-        return AuditPaginationDTO.builder()
-                .totalPageCount(count)
-                .audit(auditDTOs)
-                .userFilter(userFilter)
-                .resourceNameFilter(resourceNameFilter)
-                .resourceTypeFilter(resourceTypeFilter)
-                .projectFilter(projectFilter)
-                .build();
-    }
-
-    private Set<String> getFilter(Document document, String facet, String field) {
-        return ((List<Document>) document.get(facet))
-                .stream()
-                .map(d -> (Document) d.get(ID))
-                .map(d -> d.getString(field))
-                .collect(Collectors.toSet());
-    }
-
-    private Instant getInstant(String dateStart) {
-        Instant from;
-        try {
-            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
-            simpleDateFormat.setTimeZone(TimeZone.getTimeZone(ZoneOffset.UTC));
-            from = simpleDateFormat.parse(dateStart).toInstant();
-        } catch (ParseException e) {
-            throw new DlabException(String.format("Cannot parse %s", dateStart), e);
-        }
-        return from;
-    }
-
-    private void inCriteria(List<Bson> searchCriteria, List<String> users, String user) {
-        if (CollectionUtils.isNotEmpty(users)) {
-            searchCriteria.add(in(user, users));
-        }
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BackupDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BackupDAO.java
deleted file mode 100644
index 1a2a11c..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BackupDAO.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.resources.dto.BackupInfoRecord;
-import com.epam.dlab.dto.backup.EnvBackupDTO;
-import com.epam.dlab.dto.backup.EnvBackupStatus;
-
-import java.util.List;
-import java.util.Optional;
-
-public interface BackupDAO {
-	void createOrUpdate(EnvBackupDTO dto, String user, EnvBackupStatus status);
-
-	List<BackupInfoRecord> getBackups(String userName);
-
-	Optional<BackupInfoRecord> getBackup(String userName, String id);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BackupDAOImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BackupDAOImpl.java
deleted file mode 100644
index 4ed2788..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BackupDAOImpl.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.resources.dto.BackupInfoRecord;
-import com.epam.dlab.dto.backup.EnvBackupDTO;
-import com.epam.dlab.dto.backup.EnvBackupStatus;
-import com.google.inject.Singleton;
-import org.bson.Document;
-
-import java.util.Date;
-import java.util.List;
-import java.util.Optional;
-
-import static com.epam.dlab.backendapi.dao.MongoCollections.REQUEST_ID;
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.eq;
-
-@Singleton
-public class BackupDAOImpl extends BaseDAO implements BackupDAO {
-	@Override
-	public void createOrUpdate(EnvBackupDTO dto, String user, EnvBackupStatus status) {
-		final Document idField = backupId(user, dto.getId());
-		final Document backupDocument = convertToBson(dto)
-				.append(STATUS, status.name())
-				.append(ERROR_MESSAGE, status.message())
-				.append(TIMESTAMP, new Date())
-				.append(ID, idField);
-		updateOne(MongoCollections.BACKUPS,
-				and(eq(ID, idField), eq(REQUEST_ID, dto.getId())),
-				new Document(SET, backupDocument), true);
-	}
-
-	@Override
-	public List<BackupInfoRecord> getBackups(String userName) {
-		return find(MongoCollections.BACKUPS, eq(String.format("%s.%s", ID, USER), userName), BackupInfoRecord.class);
-	}
-
-	@Override
-	public Optional<BackupInfoRecord> getBackup(String userName, String id) {
-		return findOne(MongoCollections.BACKUPS, eq(ID, backupId(userName, id)), BackupInfoRecord.class);
-	}
-
-	private Document backupId(String user, String id) {
-		return new Document(USER, user).append(REQUEST_ID, id);
-	}
-
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java
deleted file mode 100644
index 56a77a0..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * 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.BillingReportLine;
-import com.epam.dlab.backendapi.resources.dto.BillingFilter;
-import com.epam.dlab.dto.billing.BillingResourceType;
-import com.google.inject.Inject;
-import com.mongodb.client.model.Aggregates;
-import com.mongodb.client.model.Filters;
-import com.mongodb.client.model.Sorts;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
-
-import static com.epam.dlab.backendapi.dao.MongoCollections.BILLING;
-import static com.mongodb.client.model.Accumulators.max;
-import static com.mongodb.client.model.Accumulators.min;
-import static com.mongodb.client.model.Accumulators.sum;
-import static com.mongodb.client.model.Aggregates.group;
-import static com.mongodb.client.model.Aggregates.match;
-import static com.mongodb.client.model.Aggregates.sort;
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.gte;
-import static com.mongodb.client.model.Filters.in;
-import static com.mongodb.client.model.Filters.lte;
-import static com.mongodb.client.model.Filters.regex;
-import static java.time.temporal.TemporalAdjusters.firstDayOfMonth;
-import static java.time.temporal.TemporalAdjusters.lastDayOfMonth;
-import static java.util.Collections.singletonList;
-
-@Slf4j
-public class BaseBillingDAO extends BaseDAO implements BillingDAO {
-	private static final int ONE_HUNDRED = 100;
-	private static final String COST_FIELD = "$cost";
-	private static final String TOTAL_FIELD_NAME = "total";
-	private static final String PROJECT = "project";
-	private static final String APPLICATION = "application";
-	private static final String USAGE_DATE = "usageDate";
-	private static final String USER = "user";
-	private static final String RESOURCE_TYPE = "resource_type";
-	private static final String DLAB_ID = "dlabId";
-	private static final String FROM = "from";
-	private static final String TO = "to";
-	private static final String PRODUCT = "product";
-	private static final String CURRENCY = "currency";
-	private static final String COST = "cost";
-	private static final String RESOURCE_NAME = "resource_name";
-	private static final String ENDPOINT = "endpoint";
-	private static final String SHAPE = "shape";
-	private static final String EXPLORATORY = "exploratoryName";
-
-	@Inject
-	protected SettingsDAO settings;
-	@Inject
-	private UserSettingsDAO userSettingsDAO;
-	@Inject
-	private ProjectDAO projectDAO;
-
-	@Override
-	public Double getTotalCost() {
-		return aggregateBillingData(singletonList(group(null, sum(TOTAL_FIELD_NAME, COST_FIELD))));
-	}
-
-	@Override
-	public Double getUserCost(String user) {
-		final List<Bson> pipeline = Arrays.asList(match(eq(USER, user)),
-				group(null, sum(TOTAL_FIELD_NAME, COST_FIELD)));
-		return aggregateBillingData(pipeline);
-	}
-
-	@Override
-	public Double getOverallProjectCost(String project) {
-		final List<Bson> pipeline = Arrays.asList(match(eq(PROJECT, project)),
-				group(null, sum(TOTAL_FIELD_NAME, COST_FIELD)));
-		return aggregateBillingData(pipeline);
-	}
-
-	@Override
-	public Double getMonthlyProjectCost(String project, LocalDate date) {
-		final List<Bson> pipeline = Arrays.asList(match(
-				and(
-						eq(PROJECT, project),
-						gte(USAGE_DATE, date.with(firstDayOfMonth()).toString()),
-						lte(USAGE_DATE, date.with(lastDayOfMonth()).toString()))
-				),
-				group(null, sum(TOTAL_FIELD_NAME, COST_FIELD)));
-		return aggregateBillingData(pipeline);
-	}
-
-	@Override
-	public int getBillingQuoteUsed() {
-		return toPercentage(() -> settings.getMaxBudget(), getTotalCost());
-	}
-
-	@Override
-	public int getBillingUserQuoteUsed(String user) {
-		return toPercentage(() -> userSettingsDAO.getAllowedBudget(user), getUserCost(user));
-	}
-
-	@Override
-	public boolean isBillingQuoteReached() {
-		return getBillingQuoteUsed() >= ONE_HUNDRED;
-	}
-
-	@Override
-	public boolean isUserQuoteReached(String user) {
-		final Double userCost = getUserCost(user);
-		return userSettingsDAO.getAllowedBudget(user)
-				.filter(allowedBudget -> userCost.intValue() != 0 && allowedBudget <= userCost)
-				.isPresent();
-	}
-
-	@Override
-	public List<BillingReportLine> findBillingData(String project, String endpoint, List<String> resourceNames) {
-		return find(BILLING, and(eq(PROJECT, project), eq(ENDPOINT, endpoint), in(RESOURCE_NAME, resourceNames)), BillingReportLine.class);
-	}
-
-	public List<BillingReportLine> aggregateBillingData(BillingFilter filter) {
-		List<Bson> pipeline = new ArrayList<>();
-		List<Bson> matchCriteria = matchCriteria(filter);
-		if (!matchCriteria.isEmpty()) {
-			pipeline.add(Aggregates.match(Filters.and(matchCriteria)));
-		}
-		pipeline.add(groupCriteria());
-		pipeline.add(usageDateSort());
-		return StreamSupport.stream(getCollection(BILLING).aggregate(pipeline).spliterator(), false)
-				.map(this::toBillingReport)
-				.collect(Collectors.toList());
-	}
-
-	@Override
-	public void deleteByUsageDate(String application, String usageDate) {
-		deleteMany(BILLING, and(eq(APPLICATION, application), eq(USAGE_DATE, usageDate)));
-	}
-
-	@Override
-	public void deleteByUsageDateRegex(String application, String usageDate) {
-		deleteMany(BILLING, and(eq(APPLICATION, application), regex(USAGE_DATE, "^" + usageDate)));
-	}
-
-	@Override
-	public void save(List<BillingReportLine> billingData) {
-		if (CollectionUtils.isNotEmpty(billingData)) {
-			insertMany(BILLING, new ArrayList<>(billingData));
-		}
-	}
-
-	private Integer toPercentage(Supplier<Optional<Integer>> allowedBudget, Double totalCost) {
-		return allowedBudget.get()
-				.map(userBudget -> (totalCost * ONE_HUNDRED) / userBudget)
-				.map(Double::intValue)
-				.orElse(BigDecimal.ZERO.intValue());
-	}
-
-	private Double aggregateBillingData(List<Bson> pipeline) {
-		return Optional.ofNullable(aggregate(BILLING, pipeline).first())
-				.map(d -> d.getDouble(TOTAL_FIELD_NAME))
-				.orElse(BigDecimal.ZERO.doubleValue());
-	}
-
-	private Bson usageDateSort() {
-		return sort(Sorts.descending(USAGE_DATE));
-	}
-
-	private Bson groupCriteria() {
-		return group(getGroupingFields(USER, DLAB_ID, RESOURCE_TYPE, RESOURCE_NAME, PROJECT, PRODUCT, CURRENCY, SHAPE, EXPLORATORY),
-				sum(COST, "$" + COST),
-				min(FROM, "$" + FROM),
-				max(TO, "$" + TO));
-	}
-
-	private List<Bson> matchCriteria(BillingFilter filter) {
-		List<Bson> searchCriteria = new ArrayList<>();
-
-		if (CollectionUtils.isNotEmpty(filter.getUsers())) {
-			searchCriteria.add(in(USER, filter.getUsers()));
-		}
-		if (CollectionUtils.isNotEmpty(filter.getResourceTypes())) {
-			searchCriteria.add(in(RESOURCE_TYPE, filter.getResourceTypes()));
-		}
-		if (StringUtils.isNotEmpty(filter.getDlabId())) {
-			searchCriteria.add(regex(DLAB_ID, filter.getDlabId(), "i"));
-		}
-		if (StringUtils.isNotEmpty(filter.getDateStart())) {
-			searchCriteria.add(gte(USAGE_DATE, filter.getDateStart()));
-		}
-		if (StringUtils.isNotEmpty(filter.getDateEnd())) {
-			searchCriteria.add(lte(USAGE_DATE, filter.getDateEnd()));
-		}
-		if (CollectionUtils.isNotEmpty(filter.getProjects())) {
-			searchCriteria.add(in(PROJECT, filter.getProjects()));
-		}
-		if (CollectionUtils.isNotEmpty(filter.getProducts())) {
-			searchCriteria.add(in(PRODUCT, filter.getProducts()));
-		}
-		if (CollectionUtils.isNotEmpty(filter.getShapes())) {
-			searchCriteria.add(regex(SHAPE, "(" + String.join("|", filter.getShapes()) + ")"));
-		}
-
-		return searchCriteria;
-	}
-
-	private BillingReportLine toBillingReport(Document d) {
-		Document id = (Document) d.get("_id");
-		return BillingReportLine.builder()
-				.dlabId(id.getString(DLAB_ID))
-				.project(id.getString(PROJECT))
-				.resourceName(id.getString(RESOURCE_NAME))
-				.exploratoryName(id.getString(EXPLORATORY))
-				.shape(id.getString(SHAPE))
-				.user(id.getString(USER))
-				.product(id.getString(PRODUCT))
-				.resourceType(Optional.ofNullable(id.getString(RESOURCE_TYPE)).map(BillingResourceType::valueOf).orElse(null))
-				.usageDateFrom(d.getDate(FROM).toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
-				.usageDateTo(d.getDate(TO).toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
-				.cost(BigDecimal.valueOf(d.getDouble(COST)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue())
-				.currency(id.getString(CURRENCY))
-				.build();
-	}
-}
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
deleted file mode 100644
index 253fc7b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseDAO.java
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * 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.dto.UserInstanceStatus;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.mongo.MongoService;
-import com.epam.dlab.util.mongo.modules.IsoDateModule;
-import com.epam.dlab.util.mongo.modules.JavaPrimitiveModule;
-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;
-import com.mongodb.client.AggregateIterable;
-import com.mongodb.client.FindIterable;
-import com.mongodb.client.MongoCollection;
-import com.mongodb.client.MongoCursor;
-import com.mongodb.client.MongoIterable;
-import com.mongodb.client.model.UpdateOptions;
-import com.mongodb.client.result.DeleteResult;
-import com.mongodb.client.result.UpdateResult;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.UUID;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.exists;
-import static com.mongodb.client.model.Filters.ne;
-
-/**
- * Implements the base API for Mongo database.
- */
-public class BaseDAO {
-
-	public static final String ID = "_id";
-	public static final String USER = "user";
-	public static final String STATUS = "status";
-	public static final String ERROR_MESSAGE = "error_message";
-	protected static final String INSTANCE_ID = "instance_id";
-	protected static final String EDGE_STATUS = "edge_status";
-	protected static final String ADD_TO_SET = "$addToSet";
-	protected static final String UNSET_OPERATOR = "$unset";
-	static final String FIELD_SET_DELIMETER = ".$.";
-	static final String SET = "$set";
-	static final String TIMESTAMP = "timestamp";
-	static final String REUPLOAD_KEY_REQUIRED = "reupload_key_required";
-	private static final Logger LOGGER = LoggerFactory.getLogger(BaseDAO.class);
-	private static final String INSERT_ERROR_MESSAGE = "Insert to Mongo DB fails: ";
-	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());
-	private static final String PULL = "$pull";
-	private static final String PULL_ALL = "$pullAll";
-	private static final String EACH = "$each";
-	private static final String ELEMENT_AT_OPERATOR = "$arrayElemAt";
-
-	@Inject
-	protected MongoService mongoService;
-
-	/**
-	 * Return <b>true</b> if collection exists.
-	 *
-	 * @param name collection name.
-	 */
-	boolean collectionExists(String name) {
-		return mongoService.collectionExists(name);
-	}
-
-	/**
-	 * Return Mongo collection.
-	 *
-	 * @param collection collection name.
-	 */
-	public MongoCollection<Document> getCollection(String collection) {
-		return mongoService.getCollection(collection);
-	}
-
-	/**
-	 * Inserts the document into the collection.
-	 *
-	 * @param collection collection name.
-	 * @param supplier   document.
-	 */
-	protected void insertOne(String collection, Supplier<Document> supplier) {
-		insertOne(collection, supplier, generateUUID());
-	}
-
-	/**
-	 * Inserts the document into the collection with given the unique id.
-	 *
-	 * @param collection collection name.
-	 * @param document   document.
-	 * @param uuid       unique id.
-	 */
-	protected void insertOne(String collection, Supplier<Document> document, String uuid) {
-		try {
-			mongoService.getCollection(collection)
-					.insertOne(document.get()
-							.append(ID, uuid)
-							.append(TIMESTAMP, new Date()));
-		} catch (MongoException e) {
-			LOGGER.warn(INSERT_ERROR_MESSAGE + "{}", e.getLocalizedMessage(), e);
-			throw new DlabException("Insert to Mongo DB failed: " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Serializes the object and inserts into the collection.
-	 *
-	 * @param collection collection name.
-	 * @param object     for inserting to collection.
-	 */
-	protected void insertOne(String collection, Object object) {
-		insertOne(collection, object, generateUUID());
-	}
-
-	/**
-	 * Serializes the object and inserts into the collection.
-	 *
-	 * @param collection collection name.
-	 * @param object     for inserting to collection.
-	 * @param uuid       unique id.
-	 */
-	protected void insertOne(String collection, Object object, String uuid) {
-		try {
-			mongoService.getCollection(collection)
-					.insertOne(convertToBson(object)
-							.append(ID, uuid)
-							.append(TIMESTAMP, new Date()));
-		} catch (MongoException e) {
-			LOGGER.warn(INSERT_ERROR_MESSAGE + "{}", e.getLocalizedMessage(), e);
-			throw new DlabException(INSERT_ERROR_MESSAGE + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Serializes objects and inserts into the collection.
-	 *
-	 * @param collection collection name.
-	 * @param object     for inserting to collection.
-	 */
-	protected void insertMany(String collection, List<Object> object) {
-		try {
-			mongoService.getCollection(collection)
-					.insertMany(convertToBson(object)
-							.stream()
-							.peek(o -> {
-								o.append(ID, generateUUID());
-								o.append(TIMESTAMP, new Date());
-							})
-							.collect(Collectors.toList())
-					);
-		} catch (MongoException e) {
-			LOGGER.warn(INSERT_ERROR_MESSAGE + "{}", e.getLocalizedMessage(), e);
-			throw new DlabException(INSERT_ERROR_MESSAGE + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Updates single document in the collection by condition.
-	 *
-	 * @param collection collection name.
-	 * @param condition  condition for search documents in collection.
-	 * @param document   document.
-	 */
-	protected UpdateResult updateOne(String collection, Bson condition, Bson document) {
-		try {
-			return mongoService.getCollection(collection)
-					.updateOne(condition, document);
-		} catch (MongoException e) {
-			LOGGER.warn("Update Mongo DB fails: {}", e.getLocalizedMessage(), e);
-			throw new DlabException("Update to Mongo DB fails: " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Update or insert single document in the collection by condition.
-	 *
-	 * @param collection collection name.
-	 * @param condition  condition for search documents in collection.
-	 * @param document   document.
-	 * @param isUpsert   if <b>true</b> document will be updated or inserted.
-	 */
-	protected void updateOne(String collection, Bson condition, Bson document, boolean isUpsert) {
-		try {
-			if (isUpsert) {
-				mongoService.getCollection(collection).updateOne(condition, document,
-						new UpdateOptions().upsert(true));
-			} else {
-				mongoService.getCollection(collection).updateOne(condition, document);
-			}
-		} catch (MongoException e) {
-			LOGGER.warn("Upsert Mongo DB fails: {}", e.getLocalizedMessage(), e);
-			throw new DlabException("Upsert to Mongo DB fails: " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Updates all documents in the collection by condition.
-	 *
-	 * @param collection collection name.
-	 * @param condition  condition for search documents in collection.
-	 * @param document   document.
-	 */
-	UpdateResult updateMany(String collection, Bson condition, Bson document) {
-		try {
-			return mongoService.getCollection(collection)
-					.updateMany(condition, document);
-		} catch (MongoException e) {
-			LOGGER.warn("Update Mongo DB fails: {}", e.getLocalizedMessage(), e);
-			throw new DlabException("Update to Mongo DB fails: " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Removes single document in the collection by condition.
-	 *
-	 * @param collection collection name.
-	 * @param condition  condition for search documents in collection.
-	 */
-	protected DeleteResult deleteOne(String collection, Bson condition) {
-		try {
-			return mongoService.getCollection(collection)
-					.deleteOne(condition);
-		} catch (MongoException e) {
-			LOGGER.warn("Removing document from Mongo DB fails: {}", e.getLocalizedMessage(), e);
-			throw new DlabException("Removing document from Mongo DB fails: " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Removes many documents in the collection by condition.
-	 *
-	 * @param collection collection name.
-	 * @param condition  condition for search documents in collection.
-	 */
-	protected DeleteResult deleteMany(String collection, Bson condition) {
-		try {
-			return mongoService.getCollection(collection)
-					.deleteMany(condition);
-		} catch (MongoException e) {
-			LOGGER.warn("Removing document from Mongo DB fails: {}", e.getLocalizedMessage(), e);
-			throw new DlabException("Removing document from Mongo DB fails: " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	/**
-	 * Finds and returns all documents from the collection.
-	 *
-	 * @param collection collection name.
-	 */
-	protected FindIterable<Document> find(String collection) {
-		return mongoService.getCollection(collection).find();
-	}
-
-	/**
-	 * Finds and returns documents from the collection by condition.
-	 *
-	 * @param collection collection name.
-	 * @param condition  condition for search documents in collection.
-	 */
-	protected FindIterable<Document> find(String collection, Bson condition) {
-		return mongoService.getCollection(collection)
-				.find(condition);
-	}
-
-	/**
-	 * Finds and returns all documents from the collection converted to resulted type.
-	 *
-	 * @param collection    collection name.
-	 * @param resultedClass type of class for deserialization.
-	 */
-	protected <T> List<T> find(String collection, Class<T> resultedClass) {
-		return find(collection)
-				.into(new ArrayList<>())
-				.stream()
-				.map(d -> convertFromDocument(d, resultedClass))
-				.collect(Collectors.toList());
-	}
-
-	/**
-	 * Finds and returns documents from the collection by condition.
-	 *
-	 * @param collection    collection name.
-	 * @param condition     condition for search documents in collection.
-	 * @param resultedClass type of class for deserialization.
-	 */
-	protected <T> List<T> find(String collection, Bson condition, Class<T> resultedClass) {
-		return mongoService.getCollection(collection)
-				.find(condition)
-				.into(new ArrayList<>())
-				.stream()
-				.map(d -> convertFromDocument(d, resultedClass))
-				.collect(Collectors.toList());
-	}
-
-	/**
-	 * Finds and returns documents with the specified fields from the collection by condition.
-	 *
-	 * @param collection collection name.
-	 * @param condition  condition for search documents in collection.
-	 * @param projection document describing the fields in the collection to return.
-	 */
-	protected FindIterable<Document> find(String collection, Bson condition, Bson projection) {
-		return mongoService.getCollection(collection)
-				.find(condition)
-				.projection(projection);
-	}
-
-	/**
-	 * Aggregates and returns documents according to the specified aggregation pipeline.
-	 *
-	 * @param collection collection name.
-	 * @param pipeline   the aggregate pipeline.
-	 */
-	public AggregateIterable<Document> aggregate(String collection, List<? extends Bson> pipeline) {
-		return mongoService.getCollection(collection)
-				.aggregate(pipeline);
-	}
-
-	/**
-	 * Checks that the documents iterator have one document only.
-	 *
-	 * @param documents documents
-	 */
-	private Optional<Document> limitOne(MongoIterable<Document> documents) {
-		Document first = documents.first();
-		try (MongoCursor<Document> iterator = documents.iterator()) {
-			if (iterator.hasNext()) {
-				iterator.next();
-				if (iterator.hasNext()) {
-					throw new DlabException("too many items found while one is expected");
-				}
-			}
-		}
-		return Optional.ofNullable(first);
-	}
-
-	/**
-	 * Finds and returns one document from the collection by condition.
-	 *
-	 * @param collection collection name.
-	 * @param condition  condition for search documents in collection.
-	 * @throws DlabException if documents iterator have more than one document.
-	 */
-	protected Optional<Document> findOne(String collection, Bson condition) {
-		FindIterable<Document> found = find(collection, condition);
-		return limitOne(found);
-	}
-
-	/**
-	 * Finds and returns one document with the specified fields from the collection by condition.
-	 *
-	 * @param collection collection name.
-	 * @param condition  condition for search documents in collection.
-	 * @param projection document describing the fields in the collection to return.
-	 * @throws DlabException if documents iterator have more than one document.
-	 */
-	protected Optional<Document> findOne(String collection, Bson condition, Bson projection) {
-		FindIterable<Document> found = find(collection, condition, projection);
-		return limitOne(found);
-	}
-
-	/**
-	 * Serializes given object to document and returns it.
-	 *
-	 * @param object object
-	 */
-	Document convertToBson(Object object) {
-		try {
-			return Document.parse(MAPPER.writeValueAsString(object));
-		} catch (IOException e) {
-			throw new DlabException("error converting to bson", e);
-		}
-	}
-
-	List<Document> convertToBson(List<Object> objects) {
-		return objects
-				.stream()
-				.map(this::convertToBson)
-				.collect(Collectors.toList());
-	}
-
-	/**
-	 * Finds and returns one object as given class from the collection by condition.
-	 *
-	 * @param collection collection name.
-	 * @param condition  condition for search documents in collection.
-	 * @param clazz      type of class for deserialization.
-	 */
-	protected <T> Optional<T> findOne(String collection, Bson condition, Class<T> clazz) {
-		Optional<Document> doc = findOne(collection, condition);
-		return doc.map(document -> convertFromDocument(document, clazz));
-	}
-
-	/**
-	 * Finds and returns one object as given class and with the specified fields from the collection by condition.
-	 *
-	 * @param collection collection name.
-	 * @param condition  condition for search documents in collection.
-	 * @param projection document describing the fields in the collection to return.
-	 * @param clazz      type of class for deserialization.
-	 */
-	protected <T> Optional<T> findOne(String collection, Bson condition, Bson projection, Class<T> clazz) {
-		Optional<Document> doc = findOne(collection, condition, projection);
-		return doc.map(document -> convertFromDocument(document, clazz));
-	}
-
-	/**
-	 * Deserializes given document to object and returns it.
-	 *
-	 * @param document element from database
-	 */
-	<T> T convertFromDocument(Document document, Class<T> clazz) {
-		try {
-			String json = document.toJson();
-			return MAPPER.readValue(json, clazz);
-		} catch (IOException e) {
-			throw new DlabException("error converting from document with id " + document.get(ID), e);
-		}
-	}
-
-	<T> T convertFromDocument(List<Document> documents, TypeReference<T> valueTypeRef) {
-		final String jsonArray = documents.stream()
-				.map(Document::toJson)
-				.collect(Collectors.joining(",", "[", "]"));
-		try {
-			return MAPPER.readValue(jsonArray, valueTypeRef);
-		} catch (IOException e) {
-			throw new DlabException("error converting array " + jsonArray, e);
-		}
-	}
-
-	protected Document getGroupingFields(String... fieldNames) {
-		Document d = new Document();
-		for (String name : fieldNames) {
-			d.put(name, "$" + name);
-		}
-		return d;
-	}
-
-	protected Stream<Document> stream(Iterable<Document> iterable) {
-		return StreamSupport.stream(iterable.spliterator(), false);
-	}
-
-	List<String> statusList(UserInstanceStatus[] statuses) {
-		return Arrays.stream(statuses).map(UserInstanceStatus::toString).collect(Collectors.toList());
-	}
-
-	List<String> statusList(List<UserInstanceStatus> statuses) {
-		return statuses.stream().map(UserInstanceStatus::toString).collect(Collectors.toList());
-	}
-
-	/**
-	 * Returns a unique id.
-	 */
-	private String generateUUID() {
-		return UUID.randomUUID().toString();
-	}
-
-	protected BasicDBObject addToSet(String columnName, Set<String> values) {
-		return new BasicDBObject(ADD_TO_SET, new BasicDBObject(columnName, new BasicDBObject(EACH, values)));
-	}
-
-	protected Bson unset(String columnName, String value) {
-		return new BasicDBObject(UNSET_OPERATOR, new BasicDBObject(columnName, value));
-	}
-
-	protected BasicDBObject pull(String columnName, String value) {
-		return new BasicDBObject(PULL, new BasicDBObject(columnName, value));
-	}
-
-	protected BasicDBObject pullAll(String columnName, Set<String> values) {
-		return new BasicDBObject(PULL_ALL, new BasicDBObject(columnName, values));
-	}
-
-	protected Document elementAt(String arrayColumnName, int index) {
-		return new Document(ELEMENT_AT_OPERATOR, Arrays.asList("$" + arrayColumnName, index));
-	}
-
-	protected Document elementAt(Bson bson, int index) {
-		return new Document(ELEMENT_AT_OPERATOR, Arrays.asList(bson, index));
-	}
-
-	protected Bson notNull(String fieldName) {
-		return and(exists(fieldName), ne(fieldName, null));
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java
deleted file mode 100644
index 088c319..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.BillingReportLine;
-import com.epam.dlab.backendapi.resources.dto.BillingFilter;
-
-import java.time.LocalDate;
-import java.util.List;
-
-public interface BillingDAO {
-	Double getTotalCost();
-
-	Double getUserCost(String user);
-
-	Double getOverallProjectCost(String project);
-
-	Double getMonthlyProjectCost(String project, LocalDate date);
-
-	int getBillingQuoteUsed();
-
-	int getBillingUserQuoteUsed(String user);
-
-	boolean isBillingQuoteReached();
-
-	boolean isUserQuoteReached(String user);
-
-	List<BillingReportLine> findBillingData(String project, String endpoint, List<String> resourceNames);
-
-	List<BillingReportLine> aggregateBillingData(BillingFilter filter);
-
-	void deleteByUsageDate(String application, String usageDate);
-
-	void deleteByUsageDateRegex(String application, String usageDate);
-
-	void save(List<BillingReportLine> billingData);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ComputationalDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ComputationalDAO.java
deleted file mode 100644
index 683f8fc..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ComputationalDAO.java
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * 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.util.DateRemoverUtil;
-import com.epam.dlab.dto.ResourceURL;
-import com.epam.dlab.dto.SchedulerJobDTO;
-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.base.DataEngineType;
-import com.epam.dlab.dto.computational.ComputationalStatusDTO;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.exceptions.DlabException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.mongodb.client.model.Filters;
-import com.mongodb.client.result.UpdateResult;
-import lombok.extern.slf4j.Slf4j;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.COMPUTATIONAL_RESOURCES;
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.UPTIME;
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.exploratoryCondition;
-import static com.epam.dlab.backendapi.dao.MongoCollections.USER_INSTANCES;
-import static com.epam.dlab.backendapi.dao.SchedulerJobDAO.SCHEDULER_DATA;
-import static com.epam.dlab.dto.UserInstanceStatus.TERMINATED;
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.in;
-import static com.mongodb.client.model.Filters.ne;
-import static com.mongodb.client.model.Filters.not;
-import static com.mongodb.client.model.Projections.elemMatch;
-import static com.mongodb.client.model.Projections.excludeId;
-import static com.mongodb.client.model.Projections.fields;
-import static com.mongodb.client.model.Projections.include;
-import static com.mongodb.client.model.Updates.push;
-import static com.mongodb.client.model.Updates.set;
-import static java.util.stream.Collectors.toList;
-
-/**
- * DAO for user computational resources.
- */
-@Slf4j
-public class ComputationalDAO extends BaseDAO {
-	static final String COMPUTATIONAL_NAME = "computational_name";
-	static final String COMPUTATIONAL_ID = "computational_id";
-	static final String PROJECT = "project";
-
-	static final String IMAGE = "image";
-	private static final String COMPUTATIONAL_URL = "computational_url";
-	private static final String EXPLORATORY_NAME = "exploratory_name";
-	private static final String COMPUTATIONAL_URL_DESC = "description";
-	private static final String COMPUTATIONAL_URL_URL = "url";
-	private static final String COMPUTATIONAL_LAST_ACTIVITY = "last_activity";
-	private static final String CONFIG = "config";
-
-	private static String computationalFieldFilter(String fieldName) {
-		return COMPUTATIONAL_RESOURCES + FIELD_SET_DELIMETER + fieldName;
-	}
-
-	private static Bson computationalCondition(String user, String project, String exploratoryName, String compName) {
-		return and(eq(USER, user), eq(PROJECT, project), eq(EXPLORATORY_NAME, exploratoryName),
-				eq(COMPUTATIONAL_RESOURCES + "." + COMPUTATIONAL_NAME, compName));
-	}
-
-	/**
-	 * Add the user's computational resource for notebook into database.
-	 *
-	 * @param user             user name.
-	 * @param exploratoryName  name of exploratory.
-	 * @param project          name of project
-	 * @param computationalDTO object of computational resource.
-	 * @return <b>true</b> if operation was successful, otherwise <b>false</b>.
-	 */
-	public boolean addComputational(String user, String exploratoryName, String project,
-									UserComputationalResource computationalDTO) {
-		final UpdateResult updateResult = updateOne(USER_INSTANCES,
-				and(exploratoryCondition(user, exploratoryName, project),
-						not(elemMatch(COMPUTATIONAL_RESOURCES,
-								eq(COMPUTATIONAL_NAME, computationalDTO.getComputationalName())))),
-				push(COMPUTATIONAL_RESOURCES, convertToBson(computationalDTO)));
-		return updateResult.getModifiedCount() > 0;
-	}
-
-	/**
-	 * Finds and returns the of computational resource.
-	 *
-	 * @param user              user name.
-	 * @param project           project name
-	 * @param exploratoryName   the name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @throws DlabException if exception occurs
-	 */
-	public UserComputationalResource fetchComputationalFields(String user, String project, String exploratoryName,
-															  String computationalName) {
-		Optional<UserInstanceDTO> opt = findOne(USER_INSTANCES,
-				and(exploratoryCondition(user, exploratoryName, project),
-						Filters.elemMatch(COMPUTATIONAL_RESOURCES, eq(COMPUTATIONAL_NAME, computationalName))),
-				fields(include(COMPUTATIONAL_RESOURCES + ".$"), excludeId()),
-				UserInstanceDTO.class);
-		return opt.map(UserInstanceDTO::getResources)
-				.filter(l -> !l.isEmpty())
-				.map(l -> l.get(0))
-				.orElseThrow(() -> new DlabException("Computational resource " + computationalName + " for user " + user + " with " +
-						"exploratory name " + exploratoryName + " not found."));
-	}
-
-	public List<UserComputationalResource> findComputationalResourcesWithStatus(String user, String project, String exploratoryName,
-																				UserInstanceStatus status) {
-		final UserInstanceDTO userInstanceDTO = findOne(USER_INSTANCES,
-				and(exploratoryCondition(user, exploratoryName, project),
-						elemMatch(COMPUTATIONAL_RESOURCES, eq(STATUS, status.toString()))),
-				fields(include(COMPUTATIONAL_RESOURCES), excludeId()),
-				UserInstanceDTO.class)
-				.orElseThrow(() -> new DlabException(String.format("Computational resource with status %s for user " +
-						"%s with exploratory name %s not found.", status, user, exploratoryName)));
-		return userInstanceDTO.getResources()
-				.stream()
-				.filter(computationalResource -> computationalResource.getStatus().equals(status.toString()))
-				.collect(toList());
-	}
-
-	/**
-	 * Updates the status of computational resource in Mongo database.
-	 *
-	 * @param dto object of computational resource status.
-	 * @return The result of an update operation.
-	 */
-	public UpdateResult updateComputationalStatus(ComputationalStatusDTO dto) {
-		try {
-			Document values = new Document(computationalFieldFilter(STATUS), dto.getStatus());
-			return updateOne(USER_INSTANCES,
-					and(exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
-							elemMatch(COMPUTATIONAL_RESOURCES,
-									and(eq(COMPUTATIONAL_NAME, dto.getComputationalName()),
-											not(eq(STATUS, TERMINATED.toString()))))),
-					new Document(SET, values));
-		} catch (Exception t) {
-			throw new DlabException("Could not update computational resource status", t);
-		}
-	}
-
-	/**
-	 * Updates the status of exploratory notebooks in Mongo database.
-	 *
-	 * @param dto object of exploratory status info.
-	 * @return The result of an update operation.
-	 */
-	public int updateComputationalStatusesForExploratory(StatusEnvBaseDTO<?> dto) {
-		Document values = new Document(computationalFieldFilter(STATUS), dto.getStatus());
-		values.append(computationalFieldFilter(UPTIME), null);
-		int count = 0;
-		UpdateResult result;
-		do {
-			result = updateOne(USER_INSTANCES,
-					and(exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
-							elemMatch(COMPUTATIONAL_RESOURCES,
-									and(not(eq(STATUS, TERMINATED.toString())),
-											not(eq(STATUS, dto.getStatus()))))),
-					new Document(SET, values));
-			count += result.getModifiedCount();
-		}
-		while (result.getModifiedCount() > 0);
-
-		return count;
-	}
-
-	public void updateComputationalStatusesForExploratory(String user, String project, String exploratoryName,
-														  UserInstanceStatus dataengineStatus,
-														  UserInstanceStatus dataengineServiceStatus,
-														  UserInstanceStatus... excludedStatuses) {
-		updateComputationalResource(user, project, exploratoryName, dataengineStatus,
-				DataEngineType.SPARK_STANDALONE, excludedStatuses);
-		updateComputationalResource(user, project, exploratoryName, dataengineServiceStatus,
-				DataEngineType.CLOUD_SERVICE, excludedStatuses);
-	}
-
-	/**
-	 * Updates the status for single computational resource in Mongo database.
-	 *
-	 * @param user              user name.
-	 * @param project           project name
-	 * @param exploratoryName   exploratory's name.
-	 * @param computationalName name of computational resource.
-	 * @param newStatus         new status of computational resource.
-	 */
-
-	public void updateStatusForComputationalResource(String user, String project, String exploratoryName,
-													 String computationalName, UserInstanceStatus newStatus) {
-		updateComputationalField(user, project, exploratoryName, computationalName, STATUS, newStatus.toString());
-	}
-
-
-	private void updateComputationalResource(String user, String project, String exploratoryName,
-											 UserInstanceStatus dataengineServiceStatus, DataEngineType cloudService,
-											 UserInstanceStatus... excludedStatuses) {
-		UpdateResult result;
-		do {
-			result = updateMany(USER_INSTANCES,
-					computationalFilter(user, project, exploratoryName,
-							dataengineServiceStatus.toString(), DataEngineType.getDockerImageName(cloudService), excludedStatuses),
-					new Document(SET,
-							new Document(computationalFieldFilter(STATUS), dataengineServiceStatus.toString())));
-		} while (result.getModifiedCount() > 0);
-	}
-
-	private Bson computationalFilter(String user, String project, String exploratoryName, String computationalStatus,
-									 String computationalImage, UserInstanceStatus[] excludedStatuses) {
-		final String[] statuses = Arrays.stream(excludedStatuses)
-				.map(UserInstanceStatus::toString)
-				.toArray(String[]::new);
-		return and(exploratoryCondition(user, exploratoryName, project),
-				elemMatch(COMPUTATIONAL_RESOURCES, and(eq(IMAGE, computationalImage),
-						not(in(STATUS, statuses)),
-						not(eq(STATUS, computationalStatus)))));
-	}
-
-	/**
-	 * Updates the info of computational resource in Mongo database.
-	 *
-	 * @param dto object of computational resource status.
-	 * @return The result of an update operation.
-	 * @throws DlabException if exception occurs
-	 */
-	public UpdateResult updateComputationalFields(ComputationalStatusDTO dto) {
-		try {
-			Document values = new Document(computationalFieldFilter(STATUS), dto.getStatus());
-			if (dto.getUptime() != null) {
-				values.append(computationalFieldFilter(UPTIME), dto.getUptime());
-			}
-			if (dto.getInstanceId() != null) {
-				values.append(computationalFieldFilter(INSTANCE_ID), dto.getInstanceId());
-			}
-			if (null != dto.getErrorMessage()) {
-				values.append(computationalFieldFilter(ERROR_MESSAGE),
-						DateRemoverUtil.removeDateFormErrorMessage(dto.getErrorMessage()));
-			}
-			if (dto.getComputationalId() != null) {
-				values.append(computationalFieldFilter(COMPUTATIONAL_ID), dto.getComputationalId());
-			}
-			if (dto.getResourceUrl() != null && !dto.getResourceUrl().isEmpty()) {
-				values.append(computationalFieldFilter(COMPUTATIONAL_URL), getResourceUrlData(dto));
-			}
-			if (dto.getLastActivity() != null) {
-				values.append(computationalFieldFilter(COMPUTATIONAL_LAST_ACTIVITY), dto.getLastActivity());
-			}
-			if (dto.getConfig() != null) {
-				values.append(computationalFieldFilter(CONFIG),
-						dto.getConfig().stream().map(this::convertToBson).collect(toList()));
-			}
-			return updateOne(USER_INSTANCES, and(exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
-					elemMatch(COMPUTATIONAL_RESOURCES,
-							and(eq(COMPUTATIONAL_NAME, dto.getComputationalName()),
-									not(eq(STATUS, TERMINATED.toString()))))),
-					new Document(SET, values));
-		} catch (Exception t) {
-			throw new DlabException("Could not update computational resource status", t);
-		}
-	}
-
-	private List<Map<String, String>> getResourceUrlData(ComputationalStatusDTO dto) {
-		return dto.getResourceUrl().stream()
-				.map(this::toUrlDocument)
-				.collect(toList());
-	}
-
-	private LinkedHashMap<String, String> toUrlDocument(ResourceURL url) {
-		LinkedHashMap<String, String> map = new LinkedHashMap<>();
-		map.put(COMPUTATIONAL_URL_DESC, url.getDescription());
-		map.put(COMPUTATIONAL_URL_URL, url.getUrl());
-		return map;
-	}
-
-	/**
-	 * Updates the requirement for reuploading key for single computational resource in Mongo database.
-	 *
-	 * @param user                user name.
-	 * @param project             project name
-	 * @param exploratoryName     exploratory's name.
-	 * @param computationalName   name of computational resource.
-	 * @param reuploadKeyRequired true/false.
-	 */
-
-	public void updateReuploadKeyFlagForComputationalResource(String user, String project, String exploratoryName,
-															  String computationalName, boolean reuploadKeyRequired) {
-		updateComputationalField(user, project, exploratoryName, computationalName, REUPLOAD_KEY_REQUIRED, reuploadKeyRequired);
-	}
-
-	/**
-	 * Returns names of computational resources which status is among existing ones. Also these resources will
-	 * have predefined type.
-	 *
-	 * @param user                  user name.
-	 * @param project               project name
-	 * @param computationalTypes    type list of computational resource which may contain 'dataengine' and/or
-	 *                              'dataengine-service'.
-	 * @param exploratoryName       name of exploratory.
-	 * @param computationalStatuses statuses of computational resource.
-	 * @return list of computational resources' names
-	 */
-
-	@SuppressWarnings("unchecked")
-	public List<String> getComputationalResourcesWhereStatusIn(String user, String project,
-															   List<DataEngineType> computationalTypes,
-															   String exploratoryName,
-															   UserInstanceStatus... computationalStatuses) {
-		return stream((List<Document>) find(USER_INSTANCES, exploratoryCondition(user, exploratoryName, project),
-				fields(include(COMPUTATIONAL_RESOURCES))).first().get(COMPUTATIONAL_RESOURCES))
-				.filter(doc ->
-						statusList(computationalStatuses).contains(doc.getString(STATUS)) &&
-								computationalTypes.contains(DataEngineType.fromDockerImageName(doc.getString(IMAGE))))
-				.map(doc -> doc.getString(COMPUTATIONAL_NAME)).collect(toList());
-	}
-
-	@SuppressWarnings("unchecked")
-	public List<ClusterConfig> getClusterConfig(String user, String project, String exploratoryName, String computationalName) {
-		return findOne(USER_INSTANCES,
-				and(exploratoryCondition(user, exploratoryName, project),
-						Filters.elemMatch(COMPUTATIONAL_RESOURCES, and(eq(COMPUTATIONAL_NAME, computationalName),
-								notNull(CONFIG)))),
-				fields(include(COMPUTATIONAL_RESOURCES + ".$"), excludeId())
-		).map(d -> ((List<Document>) d.get(COMPUTATIONAL_RESOURCES)).get(0))
-				.map(d -> convertFromDocument((List<Document>) d.get(CONFIG),
-						new TypeReference<List<ClusterConfig>>() {
-						}))
-				.orElse(Collections.emptyList());
-	}
-
-	/**
-	 * Updates computational resource's field.
-	 *
-	 * @param user              user name.
-	 * @param project           project name
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @param fieldName         computational field's name for updating.
-	 * @param fieldValue        computational field's value for updating.
-	 */
-
-	private <T> UpdateResult updateComputationalField(String user, String project, String exploratoryName, String computationalName,
-													  String fieldName, T fieldValue) {
-		return updateOne(USER_INSTANCES,
-				computationalCondition(user, project, exploratoryName, computationalName),
-				set(computationalFieldFilter(fieldName), fieldValue));
-	}
-
-	public void updateSchedulerSyncFlag(String user, String project, String exploratoryName, boolean syncFlag) {
-		final String syncStartField = SCHEDULER_DATA + ".sync_start_required";
-		UpdateResult result;
-		do {
-
-			result = updateOne(USER_INSTANCES, and(exploratoryCondition(user, exploratoryName, project),
-					elemMatch(COMPUTATIONAL_RESOURCES, and(ne(SCHEDULER_DATA, null), ne(syncStartField, syncFlag)))),
-					set(computationalFieldFilter(syncStartField), syncFlag));
-
-		} while (result.getModifiedCount() != 0);
-	}
-
-	public UpdateResult updateSchedulerDataForComputationalResource(String user, String project, String exploratoryName,
-																	String computationalName, SchedulerJobDTO dto) {
-		return updateComputationalField(user, project, exploratoryName, computationalName,
-				SCHEDULER_DATA, Objects.isNull(dto) ? null : convertToBson(dto));
-	}
-
-	public void updateLastActivity(String user, String project, String exploratoryName,
-								   String computationalName, LocalDateTime lastActivity) {
-		updateOne(USER_INSTANCES,
-				computationalCondition(user, project, exploratoryName, computationalName),
-				set(computationalFieldFilter(COMPUTATIONAL_LAST_ACTIVITY),
-						Date.from(lastActivity.atZone(ZoneId.systemDefault()).toInstant())));
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/DockerDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/DockerDAO.java
deleted file mode 100644
index c0ecfc4..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/DockerDAO.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.exceptions.DlabException;
-import org.bson.Document;
-
-import static com.epam.dlab.backendapi.dao.MongoCollections.DOCKER_ATTEMPTS;
-
-/** DAO write attempt of Docker
- * */
-public class DockerDAO extends BaseDAO {
-    public static final String RUN = "run";
-
-    /** Write the attempt of docker action.
-     * @param user user name.
-     * @param action action of docker.
-	 * @exception DlabException may be thrown
-     */
-	public void writeDockerAttempt(String user, String action) {
-        insertOne(DOCKER_ATTEMPTS, () -> new Document(USER, user).append("action", action));
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EndpointDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EndpointDAO.java
deleted file mode 100644
index f28539e..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EndpointDAO.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.EndpointDTO;
-
-import java.util.List;
-import java.util.Optional;
-
-/**
- * The interface specifies behaviour for objects, which retrieve, update, remove
- * the endpoints entities from the DataBase, according passed fields, i.e name, url, status.
- */
-public interface EndpointDAO {
-	List<EndpointDTO> getEndpoints();
-
-	List<EndpointDTO> getEndpointsWithStatus(String status);
-
-	/*** Retrieve the Endpoint entity according required name
-	 * @param name - the Endpoint regular title
-	 * @return the Optional object
-	 */
-	Optional<EndpointDTO> get(String name);
-
-	/*** Retrieve the Endpoint entity according required Endpoint URL
-	 * @param url - the Endpoint web address
-	 * @return the Optional object
-	 */
-	Optional<EndpointDTO> getEndpointWithUrl(String url);
-
-	void create(EndpointDTO endpointDTO);
-
-	void updateEndpointStatus(String name, String status);
-
-	void remove(String name);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EndpointDAOImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EndpointDAOImpl.java
deleted file mode 100644
index aec56ec..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EndpointDAOImpl.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.EndpointDTO;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.regex.Pattern;
-
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.regex;
-
-
-public class EndpointDAOImpl extends BaseDAO implements EndpointDAO {
-
-	private static final String ENDPOINTS_COLLECTION = "endpoints";
-	private static final String ENDPOINT_NAME_FIELD = "name";
-	private static final String ENDPOINT_STATUS_FIELD = "status";
-	private static final String ENDPOINT_URL_FIELD = "url";
-
-	@Override
-	public List<EndpointDTO> getEndpoints() {
-		return find(ENDPOINTS_COLLECTION, EndpointDTO.class);
-	}
-
-	@Override
-	public List<EndpointDTO> getEndpointsWithStatus(String status) {
-		return find(ENDPOINTS_COLLECTION, endpointStatusCondition(status), EndpointDTO.class);
-	}
-
-	@Override
-	public Optional<EndpointDTO> getEndpointWithUrl(String url) {
-		return findOne(ENDPOINTS_COLLECTION, endpointUrlCondition(url), EndpointDTO.class);
-	}
-
-	@Override
-	public Optional<EndpointDTO> get(String name) {
-		return findOne(ENDPOINTS_COLLECTION, endpointCondition(name), EndpointDTO.class);
-	}
-
-	@Override
-	public void create(EndpointDTO endpointDTO) {
-		insertOne(ENDPOINTS_COLLECTION, endpointDTO);
-	}
-
-	@Override
-	public void updateEndpointStatus(String name, String status) {
-		final Document updatedFiled = new Document(ENDPOINT_STATUS_FIELD, status);
-		updateOne(ENDPOINTS_COLLECTION, endpointCondition(name), new Document(SET, updatedFiled));
-	}
-
-	@Override
-	public void remove(String name) {
-		deleteOne(ENDPOINTS_COLLECTION, endpointCondition(name));
-	}
-
-	private Bson endpointCondition(String name) {
-		Pattern endPointName = Pattern.compile("^" + name + "$", Pattern.CASE_INSENSITIVE);
-		return regex(ENDPOINT_NAME_FIELD, endPointName);
-	}
-
-	private Bson endpointUrlCondition(String url) {
-		Pattern endPointUrl = Pattern.compile("^" + url + "$", Pattern.CASE_INSENSITIVE);
-		return regex(ENDPOINT_URL_FIELD, endPointUrl);
-	}
-
-	private Bson endpointStatusCondition(String status) {
-		return eq(ENDPOINT_STATUS_FIELD, status);
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EnvDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EnvDAO.java
deleted file mode 100644
index f554873..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EnvDAO.java
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.SelfServiceApplication;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.resources.aws.ComputationalResourceAws;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.status.EnvResource;
-import com.epam.dlab.dto.status.EnvResourceList;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.model.ResourceType;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.mongodb.client.model.Updates;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.COMPUTATIONAL_RESOURCES;
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.EXPLORATORY_NAME;
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.exploratoryCondition;
-import static com.epam.dlab.backendapi.dao.MongoCollections.USER_EDGE;
-import static com.epam.dlab.backendapi.dao.MongoCollections.USER_INSTANCES;
-import static com.epam.dlab.dto.UserInstanceStatus.CONFIGURING;
-import static com.epam.dlab.dto.UserInstanceStatus.CREATING;
-import static com.epam.dlab.dto.UserInstanceStatus.FAILED;
-import static com.epam.dlab.dto.UserInstanceStatus.RUNNING;
-import static com.epam.dlab.dto.UserInstanceStatus.STARTING;
-import static com.epam.dlab.dto.UserInstanceStatus.STOPPED;
-import static com.epam.dlab.dto.UserInstanceStatus.STOPPING;
-import static com.epam.dlab.dto.UserInstanceStatus.TERMINATED;
-import static com.epam.dlab.dto.UserInstanceStatus.TERMINATING;
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.in;
-import static com.mongodb.client.model.Filters.not;
-import static com.mongodb.client.model.Filters.or;
-import static com.mongodb.client.model.Projections.elemMatch;
-import static com.mongodb.client.model.Projections.excludeId;
-import static com.mongodb.client.model.Projections.fields;
-import static com.mongodb.client.model.Projections.include;
-import static java.util.Objects.nonNull;
-
-/**
- * DAO for updates of the status of environment resources.
- */
-@Singleton
-public class EnvDAO extends BaseDAO {
-	private static final Logger LOGGER = LoggerFactory.getLogger(EnvDAO.class);
-
-	private static final String EDGE_PUBLIC_IP = "public_ip";
-	private static final String COMPUTATIONAL_STATUS = COMPUTATIONAL_RESOURCES + "." + STATUS;
-	private static final String COMPUTATIONAL_STATUS_FILTER = COMPUTATIONAL_RESOURCES + FIELD_SET_DELIMETER + STATUS;
-	private static final String COMPUTATIONAL_SPOT = "slave_node_spot";
-	private static final String IMAGE = "image";
-	private static final String PROJECT = "project";
-	private static final String ENDPOINT = "endpoint";
-
-	private static final Bson INCLUDE_EDGE_FIELDS = include(INSTANCE_ID, EDGE_STATUS, EDGE_PUBLIC_IP);
-	private static final Bson INCLUDE_EXP_FIELDS = include(INSTANCE_ID, STATUS, PROJECT, ENDPOINT,
-			COMPUTATIONAL_RESOURCES + "." + INSTANCE_ID, COMPUTATIONAL_RESOURCES + "." + IMAGE, COMPUTATIONAL_STATUS,
-			EXPLORATORY_NAME, COMPUTATIONAL_RESOURCES + "." + ComputationalDAO.COMPUTATIONAL_NAME);
-	private static final Bson INCLUDE_EXP_UPDATE_FIELDS = include(EXPLORATORY_NAME, INSTANCE_ID, STATUS,
-			COMPUTATIONAL_RESOURCES + "." + ComputationalDAO.COMPUTATIONAL_NAME, COMPUTATIONAL_RESOURCES + "." +
-					INSTANCE_ID,
-			COMPUTATIONAL_STATUS, COMPUTATIONAL_RESOURCES + "." + IMAGE);
-	private static final String COMPUTATIONAL_NAME = "computational_name";
-
-	@Inject
-	private SelfServiceApplicationConfiguration configuration;
-
-	/**
-	 * Finds and returns the list of user resources.
-	 *
-	 * @param user name.
-	 */
-	public Map<String, EnvResourceList> findEnvResources(String user) {
-		List<EnvResource> hostList = new ArrayList<>();
-		List<EnvResource> clusterList = new ArrayList<>();
-
-		stream(find(USER_INSTANCES, eq(USER, user), fields(INCLUDE_EXP_FIELDS, excludeId())))
-				.forEach(exp -> {
-					final String exploratoryName = exp.getString(EXPLORATORY_NAME);
-					final String project = exp.getString(PROJECT);
-					final String endpoint = exp.getString(ENDPOINT);
-					addResource(hostList, exp, STATUS, ResourceType.EXPLORATORY, exploratoryName, project, endpoint);
-					addComputationalResources(hostList, clusterList, exp, exploratoryName);
-				});
-		final Map<String, List<EnvResource>> clustersByEndpoint = clusterList.stream()
-				.collect(Collectors.groupingBy(EnvResource::getEndpoint));
-		return hostList.stream()
-				.collect(Collectors.groupingBy(EnvResource::getEndpoint)).entrySet()
-				.stream()
-				.collect(Collectors.toMap(Map.Entry::getKey, e -> new EnvResourceList()
-						.withHostList(!e.getValue().isEmpty() ? e.getValue() : Collections.emptyList())
-						.withClusterList(clustersByEndpoint.getOrDefault(e.getKey(), clusterList))));
-	}
-
-	@SuppressWarnings("unchecked")
-	public List<UserInstanceDTO> findRunningResourcesForCheckInactivity() {
-		return stream(find(USER_INSTANCES, or(eq(STATUS, RUNNING.toString()),
-				elemMatch(COMPUTATIONAL_RESOURCES, eq(STATUS, RUNNING.toString())))))
-				.map(d -> convertFromDocument(d, UserInstanceDTO.class))
-				.collect(Collectors.toList());
-	}
-
-	private EnvResource toEnvResource(String name, String instanceId, ResourceType resType, String project,
-									  String endpoint) {
-		return new EnvResource(instanceId, name, resType, project, endpoint);
-	}
-
-	@SuppressWarnings("unchecked")
-	private void addComputationalResources(List<EnvResource> hostList, List<EnvResource> clusterList, Document exp,
-										   String exploratoryName) {
-		final String project = exp.getString(PROJECT);
-		getComputationalResources(exp)
-				.forEach(comp -> addComputational(hostList, clusterList, exploratoryName, comp, project,
-						exp.getString(ENDPOINT)));
-	}
-
-	private List<Document> getComputationalResources(Document userInstanceDocument) {
-		return (List<Document>) userInstanceDocument.getOrDefault(COMPUTATIONAL_RESOURCES, Collections.emptyList());
-	}
-
-	private void addComputational(List<EnvResource> hostList, List<EnvResource> clusterList, String exploratoryName,
-								  Document computational, String project, String endpoint) {
-		final List<EnvResource> resourceList = DataEngineType.CLOUD_SERVICE ==
-				DataEngineType.fromDockerImageName(computational.getString(IMAGE)) ? clusterList :
-				hostList;
-		addResource(resourceList, computational, STATUS, ResourceType.COMPUTATIONAL,
-				String.join("_", exploratoryName, computational.getString(COMPUTATIONAL_NAME)), project, endpoint);
-	}
-
-	/**
-	 * Updates the status of exploratory and computational for user.
-	 *
-	 * @param user    the name of user.
-	 * @param project name of project
-	 * @param list    the status of node.
-	 */
-	public void updateEnvStatus(String user, String project, EnvResourceList list) {
-		if (list != null && notEmpty(list.getHostList())) {
-			updateEdgeStatus(user, list.getHostList());
-			if (!list.getHostList().isEmpty()) {
-				stream(find(USER_INSTANCES, eq(USER, user),
-						fields(INCLUDE_EXP_UPDATE_FIELDS, excludeId())))
-						.filter(this::instanceIdPresent)
-						.forEach(exp -> updateUserResourceStatuses(user, project, list, exp));
-			}
-		}
-	}
-
-	public Set<String> fetchActiveEnvUsers() {
-		return Stream.concat(
-				stream(find(USER_INSTANCES, eq(STATUS, UserInstanceStatus.RUNNING.toString()),
-						fields(include(USER), excludeId()))).map(d -> d.getString(USER)),
-				stream(find(USER_EDGE, eq(EDGE_STATUS, UserInstanceStatus.RUNNING.toString()),
-						fields(include(ID)))).map(d -> d.getString(ID))
-		).collect(Collectors.toSet());
-	}
-
-	public Set<String> fetchUsersNotIn(Set<String> users) {
-		return stream(find(USER_EDGE, not(in(ID, users)),
-				fields(include(ID)))).map(d -> d.getString(ID))
-				.collect(Collectors.toSet());
-	}
-
-	@SuppressWarnings("unchecked")
-	private void updateUserResourceStatuses(String user, String project, EnvResourceList list, Document exp) {
-		final String exploratoryName = exp.getString(EXPLORATORY_NAME);
-		getEnvResourceAndRemove(list.getHostList(), exp.getString(INSTANCE_ID))
-				.ifPresent(resource -> updateExploratoryStatus(user, project, exploratoryName,
-						exp.getString(STATUS), resource.getStatus()));
-
-		(getComputationalResources(exp))
-				.stream()
-				.filter(this::instanceIdPresent)
-				.forEach(comp -> updateComputational(user, project, list, exploratoryName, comp));
-	}
-
-	private void updateComputational(String user, String project, EnvResourceList list, String exploratoryName, Document comp) {
-		final List<EnvResource> listToCheck = DataEngineType.CLOUD_SERVICE ==
-				DataEngineType.fromDockerImageName(comp.getString(IMAGE)) ?
-				list.getClusterList() : list.getHostList();
-		getEnvResourceAndRemove(listToCheck, comp.getString(INSTANCE_ID))
-				.ifPresent(resource -> updateComputationalStatus(user, project, exploratoryName,
-						comp.getString(ComputationalDAO.COMPUTATIONAL_NAME), comp.getString(STATUS), resource.getStatus()));
-	}
-
-	private boolean instanceIdPresent(Document d) {
-		return nonNull(d.getString(INSTANCE_ID));
-	}
-
-	private Optional<String> getInstanceId(Document document) {
-		return Optional.ofNullable(document.getString(INSTANCE_ID));
-	}
-
-
-	/**
-	 * Find and return the id of instance for EDGE node.
-	 *
-	 * @param user the name of user.
-	 */
-	private Optional<Document> getEdgeNode(String user) {
-		return findOne(USER_EDGE,
-				eq(ID, user),
-				fields(INCLUDE_EDGE_FIELDS, excludeId()));
-	}
-
-	/**
-	 * Find and return the resource item for given id (of instance or cluster) or <b>null<b> otherwise.
-	 *
-	 * @param list the list of resources.
-	 * @param id   the id of instance or cluster.
-	 */
-	private Optional<EnvResource> getEnvResourceAndRemove(List<EnvResource> list, String id) {
-		if (list != null) {
-			return IntStream.range(0, list.size())
-					.filter(i -> list.get(i).getId().equals(id))
-					.mapToObj(i -> getAndRemove(list, i)).findAny();
-		}
-		return Optional.empty();
-	}
-
-	private EnvResource getAndRemove(List<EnvResource> list, int i) {
-		final EnvResource envResource = list.get(i);
-		list.remove(i);
-		return envResource;
-	}
-
-	/**
-	 * Translate the status of instance in Amazon into exploratory's status.
-	 *
-	 * @param oldStatus the current status of exploratory.
-	 * @param newStatus the current status of instance in Amazon.
-	 */
-	private UserInstanceStatus getInstanceNewStatus(UserInstanceStatus oldStatus, String newStatus) {
-		/* AWS statuses: pending, running, shutting-down, terminated, stopping, stopped */
-		UserInstanceStatus status;
-		if ("pending".equalsIgnoreCase(newStatus) || "stopping".equalsIgnoreCase(newStatus)) {
-			return oldStatus;
-		} else if ("shutting-down".equalsIgnoreCase(newStatus)) {
-			status = TERMINATING;
-		} else {
-			status = UserInstanceStatus.of(newStatus);
-		}
-
-		switch (oldStatus) {
-			case CREATING_IMAGE:
-				return !status.in(UserInstanceStatus.TERMINATED, TERMINATING,
-						UserInstanceStatus.RUNNING) ? status : oldStatus;
-			case CREATING:
-				return (status.in(UserInstanceStatus.TERMINATED, UserInstanceStatus.STOPPED) ? status : oldStatus);
-			case RUNNING:
-			case STOPPING:
-				return (status.in(TERMINATING, UserInstanceStatus.TERMINATED,
-						UserInstanceStatus.STOPPING, UserInstanceStatus.STOPPED) ? status : oldStatus);
-			case STARTING:
-				return (status.in(TERMINATING, UserInstanceStatus.TERMINATED,
-						UserInstanceStatus.STOPPING) ? status : oldStatus);
-			case STOPPED:
-				return (status.in(TERMINATING, UserInstanceStatus.TERMINATED,
-						UserInstanceStatus.RUNNING) ? status : oldStatus);
-			case TERMINATING:
-				return (status.in(UserInstanceStatus.TERMINATED) ? status : oldStatus);
-			case FAILED:
-			case TERMINATED:
-			default:
-				return oldStatus;
-		}
-	}
-
-	/**
-	 * Updates the status of EDGE node for user.
-	 *
-	 * @param user     the name of user.
-	 * @param hostList list with instance ids for edge resources
-	 * @throws DlabException in case of exception
-	 */
-	private void updateEdgeStatus(String user, List<EnvResource> hostList) {
-		LOGGER.trace("Update EDGE status for user {}", user);
-		getEdgeNode(user)
-				.ifPresent(edge -> getInstanceId(edge)
-						.ifPresent(instanceId -> getEnvResourceAndRemove(hostList, instanceId)
-								.ifPresent(r -> updateEdgeStatus(user, edge, instanceId, r))));
-
-	}
-
-	private void updateEdgeStatus(String user, Document edge, String instanceId, EnvResource r) {
-		final String oldStatus = edge.getString(EDGE_STATUS);
-		LOGGER.trace("Update EDGE status for user {} with instance_id {} from {} to {}",
-				user, instanceId, oldStatus, r.getStatus());
-		UserInstanceStatus oStatus =
-				(oldStatus == null ? UserInstanceStatus.CREATING : UserInstanceStatus.of(oldStatus));
-		UserInstanceStatus status = oStatus != FAILED ? getInstanceNewStatus(oStatus, r.getStatus()) :
-				UserInstanceStatus.of(r.getStatus());
-		LOGGER.trace("EDGE status translated for user {} with instanceId {} from {} to {}",
-				user, instanceId, r.getStatus(), status);
-		Optional.ofNullable(status)
-				.filter(s -> s != oStatus)
-				.ifPresent(s -> {
-					LOGGER.debug("EDGE status will be updated from {} to {}", oldStatus, status);
-					updateOne(USER_EDGE, eq(ID, user),
-							Updates.set(EDGE_STATUS, status.toString()));
-				});
-	}
-
-	/**
-	 * Update the status of exploratory if it needed.
-	 *
-	 * @param user            the user name
-	 * @param project         project name
-	 * @param exploratoryName the name of exploratory
-	 * @param oldStatus       old status
-	 * @param newStatus       new status
-	 */
-	private void updateExploratoryStatus(String user, String project, String exploratoryName,
-										 String oldStatus, String newStatus) {
-		LOGGER.trace("Update exploratory status for user {} with exploratory {} from {} to {}", user, exploratoryName,
-				oldStatus, newStatus);
-		UserInstanceStatus oStatus = UserInstanceStatus.of(oldStatus);
-		UserInstanceStatus status = getInstanceNewStatus(oStatus, newStatus);
-		LOGGER.trace("Exploratory status translated for user {} with exploratory {} from {} to {}", user,
-				exploratoryName, newStatus, status);
-
-		if (oStatus != status) {
-			LOGGER.debug("Exploratory status for user {} with exploratory {} will be updated from {} to {}", user,
-					exploratoryName, oldStatus, status);
-			updateOne(USER_INSTANCES,
-					exploratoryCondition(user, exploratoryName, project),
-					Updates.set(STATUS, status.toString()));
-		}
-	}
-
-	/**
-	 * Translate the status of cluster in Amazon into computational's status.
-	 *
-	 * @param oldStatus the current status of computational.
-	 * @param newStatus the current status of cluster in Amazon.
-	 */
-	private UserInstanceStatus getComputationalNewStatus(UserInstanceStatus oldStatus, String newStatus) {
-		/* AWS statuses: bootstrapping, running, starting, terminated, terminated_with_errors, terminating, waiting */
-		UserInstanceStatus status;
-		if ("terminated".equalsIgnoreCase(newStatus) || "terminated_with_errors".equalsIgnoreCase(newStatus)) {
-			status = UserInstanceStatus.TERMINATED;
-		} else {
-			status = Optional.ofNullable(UserInstanceStatus.of(newStatus)).orElse(oldStatus);
-		}
-
-		switch (oldStatus) {
-			case CREATING:
-			case CONFIGURING:
-			case RUNNING:
-				return (status.in(UserInstanceStatus.TERMINATED, TERMINATING,
-						UserInstanceStatus.STOPPING, UserInstanceStatus.STOPPED) ? status : oldStatus);
-			case TERMINATING:
-				return (status.in(UserInstanceStatus.TERMINATED) ? status : oldStatus);
-			case STARTING:
-			case STOPPED:
-			case STOPPING:
-				return status;
-			case FAILED:
-			case TERMINATED:
-			default:
-				return oldStatus;
-		}
-	}
-
-	/**
-	 * Update the status of exploratory if it needed.
-	 *
-	 * @param user              the user name.
-	 * @param project           project name
-	 * @param exploratoryName   the name of exploratory.
-	 * @param computationalName the name of computational.
-	 * @param oldStatus         old status.
-	 * @param newStatus         new status.
-	 */
-	private void updateComputationalStatus(String user, String project, String exploratoryName, String computationalName,
-										   String oldStatus, String newStatus) {
-		LOGGER.trace("Update computational status for user {} with exploratory {} and computational {} from {} to {}",
-				user, exploratoryName, computationalName, oldStatus, newStatus);
-		UserInstanceStatus oStatus = UserInstanceStatus.of(oldStatus);
-		UserInstanceStatus status = getComputationalNewStatus(oStatus, newStatus);
-		LOGGER.trace("Translate computational status for user {} with exploratory {} and computational {} from {} to" +
-						" " +
-						"{}",
-				user, exploratoryName, computationalName, newStatus, status);
-
-		if (oStatus != status) {
-			LOGGER.debug("Computational status for user {} with exploratory {} and computational {} will be updated " +
-							"from {} to {}",
-					user, exploratoryName, computationalName, oldStatus, status);
-			if (status == UserInstanceStatus.TERMINATED &&
-					terminateComputationalSpot(user, project, exploratoryName, computationalName)) {
-				return;
-			}
-			Document values = new Document(COMPUTATIONAL_STATUS_FILTER, status.toString());
-			updateOne(USER_INSTANCES,
-					and(exploratoryCondition(user, exploratoryName, project),
-							elemMatch(COMPUTATIONAL_RESOURCES,
-									and(eq(ComputationalDAO.COMPUTATIONAL_NAME, computationalName))
-							)
-					),
-					new Document(SET, values));
-		}
-	}
-
-	/**
-	 * Terminate EMR if it is spot.
-	 *
-	 * @param user              the user name.
-	 * @param project           name of project
-	 * @param exploratoryName   the name of exploratory.
-	 * @param computationalName the name of computational.
-	 * @return <b>true</b> if computational is spot and should be terminated by docker, otherwise <b>false</b>.
-	 */
-	private boolean terminateComputationalSpot(String user, String project, String exploratoryName, String computationalName) {
-		LOGGER.trace("Check computatation is spot for user {} with exploratory {} and computational {}", user,
-				exploratoryName, computationalName);
-		Document doc = findOne(USER_INSTANCES,
-				exploratoryCondition(user, exploratoryName, project),
-				and(elemMatch(COMPUTATIONAL_RESOURCES,
-						and(eq(ComputationalDAO.COMPUTATIONAL_NAME, computationalName),
-								eq(COMPUTATIONAL_SPOT, true),
-								not(eq(STATUS, TERMINATED.toString())))),
-						include(COMPUTATIONAL_RESOURCES + "." + COMPUTATIONAL_SPOT))
-		).orElse(null);
-		if (doc == null || doc.get(COMPUTATIONAL_RESOURCES) == null) {
-			return false;
-		}
-
-		UserInfo userInfo = null;
-		if (userInfo == null) {
-			// User logged off. Computational will be terminated when user logged in.
-			return true;
-		}
-
-		String accessToken = userInfo.getAccessToken();
-		LOGGER.debug("Computational will be terminated for user {} with exploratory {} and computational {}",
-				user, exploratoryName, computationalName);
-		try {
-			// Send post request to provisioning service to terminate spot EMR.
-			ComputationalResourceAws computational = new ComputationalResourceAws();
-			SelfServiceApplication.getInjector().injectMembers(computational);
-			UserInfo ui = new UserInfo(user, accessToken);
-			computational.terminate(ui, project, exploratoryName, computationalName);
-		} catch (Exception e) {
-			// Cannot terminate EMR, just update status to terminated
-			LOGGER.warn("Can't terminate computational for user {} with exploratory {} and computational {}. {}",
-					user, exploratoryName, computationalName, e.getLocalizedMessage(), e);
-			return false;
-		}
-
-		return true;
-	}
-
-
-	/**
-	 * Add the resource to list if it have instance_id.
-	 *
-	 * @param list            the list to add.
-	 * @param document        document with resource.
-	 * @param statusFieldName name of field that contains status information
-	 * @param resourceType    type if resource EDGE/NOTEBOOK
-	 */
-	private void addResource(List<EnvResource> list, Document document, String statusFieldName,
-							 ResourceType resourceType, String name, String project, String endpoint) {
-		LOGGER.trace("Add resource from {}", document);
-		getInstanceId(document).ifPresent(instanceId ->
-				Optional.ofNullable(UserInstanceStatus.of(document.getString(statusFieldName)))
-						.filter(s -> s.in(CONFIGURING, CREATING, RUNNING, STARTING, STOPPED, STOPPING, TERMINATING) ||
-								(FAILED == s && ResourceType.EDGE == resourceType))
-						.ifPresent(s -> list.add(toEnvResource(name, instanceId, resourceType, project, endpoint))));
-	}
-
-	private boolean notEmpty(List<EnvResource> hostList) {
-		return hostList != null && !hostList.isEmpty();
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ExploratoryDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ExploratoryDAO.java
deleted file mode 100644
index 0cee441..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ExploratoryDAO.java
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- * 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.util.DateRemoverUtil;
-import com.epam.dlab.dto.ResourceURL;
-import com.epam.dlab.dto.SchedulerJobDTO;
-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.exploratory.ExploratoryStatusDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.google.inject.Singleton;
-import com.mongodb.client.result.UpdateResult;
-import lombok.extern.slf4j.Slf4j;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.backendapi.dao.MongoCollections.USER_INSTANCES;
-import static com.epam.dlab.backendapi.dao.SchedulerJobDAO.SCHEDULER_DATA;
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.in;
-import static com.mongodb.client.model.Filters.not;
-import static com.mongodb.client.model.Filters.or;
-import static com.mongodb.client.model.Projections.exclude;
-import static com.mongodb.client.model.Projections.excludeId;
-import static com.mongodb.client.model.Projections.fields;
-import static com.mongodb.client.model.Projections.include;
-import static com.mongodb.client.model.Updates.set;
-import static java.util.stream.Collectors.toList;
-
-/**
- * DAO for user exploratory.
- */
-@Slf4j
-@Singleton
-public class ExploratoryDAO extends BaseDAO {
-	public static final String COMPUTATIONAL_RESOURCES = "computational_resources";
-	static final String EXPLORATORY_ID = "exploratory_id";
-	static final String EXPLORATORY_NAME = "exploratory_name";
-	static final String UPTIME = "up_time";
-
-	private static final String COMPUTATIONAL_NAME = "computational_name";
-	private static final String EXPLORATORY_URL = "exploratory_url";
-	private static final String EXPLORATORY_URL_DESC = "description";
-	private static final String EXPLORATORY_URL_URL = "url";
-	private static final String EXPLORATORY_USER = "exploratory_user";
-	private static final String EXPLORATORY_PASS = "exploratory_pass";
-	private static final String CLUSTER_CONFIG = "cluster_config";
-	private static final String EXPLORATORY_PRIVATE_IP = "private_ip";
-	public static final String EXPLORATORY_NOT_FOUND_MSG = "Exploratory for user %s with name %s not found";
-	private static final String EXPLORATORY_LAST_ACTIVITY = "last_activity";
-	private static final String PROJECT = "project";
-	private static final String ENDPOINT = "endpoint";
-
-	public ExploratoryDAO() {
-		log.info("{} is initialized", getClass().getSimpleName());
-	}
-
-	static Bson exploratoryCondition(String user, String exploratoryName, String project) {
-		return and(eq(USER, user), eq(EXPLORATORY_NAME, exploratoryName), eq(PROJECT, project));
-	}
-
-	private static Bson runningExploratoryCondition(String user, String exploratoryName, String project) {
-		return and(eq(USER, user), eq(PROJECT, project),
-				and(eq(EXPLORATORY_NAME, exploratoryName), eq(STATUS, UserInstanceStatus.RUNNING.toString())));
-	}
-
-	static Bson runningExploratoryAndComputationalCondition(String user, String project, String exploratoryName,
-															String computationalName) {
-		return and(eq(USER, user), eq(PROJECT, project),
-				and(eq(EXPLORATORY_NAME, exploratoryName), eq(STATUS, UserInstanceStatus.RUNNING.toString()),
-						eq(COMPUTATIONAL_RESOURCES + "." + COMPUTATIONAL_NAME, computationalName),
-						eq(COMPUTATIONAL_RESOURCES + "." + STATUS, UserInstanceStatus.RUNNING.toString())));
-	}
-
-	public List<UserInstanceDTO> findExploratories(String user, String project) {
-		return getUserInstances(and(eq(USER, user), eq(PROJECT, project)), true);
-	}
-
-	/**
-	 * Finds and returns the info of all user's running notebooks.
-	 *
-	 * @param user user name.
-	 */
-	public List<UserInstanceDTO> fetchRunningExploratoryFields(String user) {
-		return getUserInstances(and(eq(USER, user), eq(STATUS, UserInstanceStatus.RUNNING.toString())), false);
-	}
-
-	public List<UserInstanceDTO> fetchRunningExploratoryFieldsForProject(String project) {
-		return getUserInstances(and(eq(PROJECT, project), eq(STATUS, UserInstanceStatus.RUNNING.toString())), false);
-	}
-
-	public List<UserInstanceDTO> fetchRunningExploratoryFieldsForProject(String project, List<String> endpoints) {
-		return getUserInstances(and(eq(PROJECT, project), eq(STATUS, UserInstanceStatus.RUNNING.toString()), in(ENDPOINT, endpoints)), false);
-	}
-
-	public List<UserInstanceDTO> fetchExploratoryFieldsForProject(String project) {
-		return getUserInstances(and(eq(PROJECT, project)), false);
-	}
-
-	public List<UserInstanceDTO> fetchExploratoryFieldsForProjectWithComp(String project) {
-		return getUserInstances(and(eq(PROJECT, project)), true);
-	}
-
-	public List<UserInstanceDTO> fetchExploratoryFieldsForProjectWithComp(List<String> projects) {
-		return getUserInstances(and(in(PROJECT, projects)), true);
-	}
-
-	public List<UserInstanceDTO> findExploratories(String project, String endpoint, String user) {
-		return getUserInstances(and(eq(PROJECT, project), eq(ENDPOINT, endpoint), eq(USER, user)), true);
-	}
-
-	public List<UserInstanceDTO> fetchUserExploratoriesWhereStatusIn(String user, boolean computationalFieldsRequired,
-																	 UserInstanceStatus... statuses) {
-		final List<String> statusList = statusList(statuses);
-		return getUserInstances(
-				and(
-						eq(USER, user),
-						in(STATUS, statusList)
-				),
-				computationalFieldsRequired);
-	}
-
-	/**
-	 * Finds and returns the info of all user's notebooks whose status or status of affiliated computational resource
-	 * is present among predefined ones.
-	 *
-	 * @param user                  user name.
-	 * @param exploratoryStatuses   array of exploratory statuses.
-	 * @param computationalStatuses array of computational statuses.
-	 */
-	public List<UserInstanceDTO> fetchUserExploratoriesWhereStatusIn(String user,
-																	 List<UserInstanceStatus> exploratoryStatuses,
-																	 UserInstanceStatus... computationalStatuses) {
-		final List<String> exploratoryStatusList = statusList(exploratoryStatuses);
-		final List<String> computationalStatusList = statusList(computationalStatuses);
-		return getUserInstances(
-				and(
-						eq(USER, user),
-						or(in(STATUS, exploratoryStatusList),
-								in(COMPUTATIONAL_RESOURCES + "." + STATUS, computationalStatusList))
-				),
-				false);
-	}
-
-	public List<UserInstanceDTO> fetchProjectExploratoriesWhereStatusIn(String project,
-																		List<UserInstanceStatus> exploratoryStatuses,
-																		UserInstanceStatus... computationalStatuses) {
-		final List<String> exploratoryStatusList = statusList(exploratoryStatuses);
-		final List<String> computationalStatusList = statusList(computationalStatuses);
-		return getUserInstances(
-				and(
-						eq(PROJECT, project),
-						or(in(STATUS, exploratoryStatusList),
-								in(COMPUTATIONAL_RESOURCES + "." + STATUS, computationalStatusList))
-				),
-				false);
-	}
-
-	public List<UserInstanceDTO> fetchProjectEndpointExploratoriesWhereStatusIn(String project, List<String> endpoints,
-																				List<UserInstanceStatus> exploratoryStatuses,
-																				UserInstanceStatus... computationalStatuses) {
-		final List<String> exploratoryStatusList = statusList(exploratoryStatuses);
-		final List<String> computationalStatusList = statusList(computationalStatuses);
-		return getUserInstances(
-				and(
-						eq(PROJECT, project),
-						in(ENDPOINT, endpoints),
-						or(in(STATUS, exploratoryStatusList),
-								in(COMPUTATIONAL_RESOURCES + "." + STATUS, computationalStatusList))
-				),
-				false);
-	}
-
-	public List<UserInstanceDTO> fetchProjectExploratoriesWhereStatusNotIn(String project, String endpoint,
-																		   UserInstanceStatus... statuses) {
-		final List<String> statusList = statusList(statuses);
-		return getUserInstances(
-				and(
-						eq(PROJECT, project),
-						eq(ENDPOINT, endpoint),
-						not(in(STATUS, statusList))
-				),
-				false);
-	}
-
-	public List<UserInstanceDTO> fetchExploratoriesByEndpointWhereStatusNotIn(String endpoint,
-																			  List<UserInstanceStatus> statuses) {
-		final List<String> exploratoryStatusList = statusList(statuses);
-
-		return getUserInstances(
-				and(
-						eq(ENDPOINT, endpoint),
-						not(in(STATUS, exploratoryStatusList))
-				),
-				false);
-	}
-
-	private List<UserInstanceDTO> getUserInstances(Bson condition, boolean computationalFieldsRequired) {
-		return stream(getCollection(USER_INSTANCES)
-				.find(condition)
-				.projection(computationalFieldsRequired ? null : fields(exclude(COMPUTATIONAL_RESOURCES))))
-				.map(d -> convertFromDocument(d, UserInstanceDTO.class))
-				.collect(Collectors.toList());
-	}
-
-	/**
-	 * Finds and returns the info about all exploratories in database.
-	 **/
-	public List<UserInstanceDTO> getInstances() {
-		return stream(getCollection(USER_INSTANCES)
-				.find())
-				.map(d -> convertFromDocument(d, UserInstanceDTO.class))
-				.collect(Collectors.toList());
-	}
-
-	public void updateLastActivity(String user, String exploratoryName, LocalDateTime lastActivity) {
-		updateOne(USER_INSTANCES, and(eq(USER, user), eq(EXPLORATORY_NAME, exploratoryName)),
-				set(EXPLORATORY_LAST_ACTIVITY, toDate(lastActivity)));
-	}
-
-	private Date toDate(LocalDateTime lastActivity) {
-		return Date.from(lastActivity.atZone(ZoneId.systemDefault()).toInstant());
-	}
-
-	/**
-	 * Finds and returns the info of exploratory (without info about computational resources).
-	 *
-	 * @param user            user name.
-	 * @param project         project name
-	 * @param exploratoryName the name of exploratory.
-	 */
-	public UserInstanceDTO fetchExploratoryFields(String user, String project, String exploratoryName) {
-		return getExploratory(user, project, exploratoryName, false).orElseThrow(() ->
-				new ResourceNotFoundException(String.format(EXPLORATORY_NOT_FOUND_MSG, user, exploratoryName)));
-
-	}
-
-	public UserInstanceDTO fetchExploratoryFields(String user, String project, String exploratoryName, boolean includeCompResources) {
-		return getExploratory(user, project, exploratoryName, includeCompResources).orElseThrow(() ->
-				new ResourceNotFoundException(String.format(EXPLORATORY_NOT_FOUND_MSG, user, exploratoryName)));
-
-	}
-
-	private Optional<UserInstanceDTO> getExploratory(String user, String project, String exploratoryName,
-													 boolean includeCompResources) {
-		return findOne(USER_INSTANCES,
-				exploratoryCondition(user, exploratoryName, project),
-				includeCompResources ? null : fields(exclude(COMPUTATIONAL_RESOURCES)),
-				UserInstanceDTO.class);
-	}
-
-	/**
-	 * Finds and returns the info of running exploratory with running cluster.
-	 *
-	 * @param user              user name.
-	 * @param project           name of project
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of cluster
-	 */
-	public UserInstanceDTO fetchExploratoryFields(String user, String project, String exploratoryName, String computationalName) {
-		return findOne(USER_INSTANCES,
-				runningExploratoryAndComputationalCondition(user, project, exploratoryName, computationalName),
-				UserInstanceDTO.class)
-				.orElseThrow(() -> new DlabException(String.format("Running notebook %s with running cluster %s not " +
-								"found for user %s",
-						exploratoryName, computationalName, user)));
-	}
-
-	/**
-	 * Finds and returns the info of running exploratory.
-	 *
-	 * @param user            user name.
-	 * @param project         project
-	 * @param exploratoryName name of exploratory.
-	 */
-	public UserInstanceDTO fetchRunningExploratoryFields(String user, String project, String exploratoryName) {
-		return findOne(USER_INSTANCES, runningExploratoryCondition(user, exploratoryName, project),
-				fields(exclude(COMPUTATIONAL_RESOURCES)), UserInstanceDTO.class)
-				.orElseThrow(() -> new DlabException(
-						String.format("Running exploratory instance for user %s with name %s not found.",
-								user, exploratoryName)));
-	}
-
-	/**
-	 * Inserts the info about notebook into Mongo database.
-	 *
-	 * @param dto the info about notebook
-	 */
-	public void insertExploratory(UserInstanceDTO dto) {
-		insertOne(USER_INSTANCES, dto);
-	}
-
-	/**
-	 * Updates the status of exploratory in Mongo database.
-	 *
-	 * @param dto object of exploratory status info.
-	 * @return The result of an update operation.
-	 */
-	public UpdateResult updateExploratoryStatus(StatusEnvBaseDTO<?> dto) {
-		return updateOne(USER_INSTANCES,
-				exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
-				set(STATUS, dto.getStatus()));
-	}
-
-	/**
-	 * Updates status for single exploratory in Mongo database.
-	 *
-	 * @param user            user.
-	 * @param project         project name
-	 * @param exploratoryName name of exploratory.
-	 * @param newStatus       new status of exploratory.
-	 * @return The result of an update operation.
-	 */
-	public UpdateResult updateStatusForExploratory(String user, String project, String exploratoryName, UserInstanceStatus newStatus) {
-		return updateOne(USER_INSTANCES,
-				exploratoryCondition(user, exploratoryName, project),
-				set(STATUS, newStatus.toString()));
-	}
-
-	/**
-	 * Updates the scheduler's data for exploratory in Mongo database.
-	 *
-	 * @param user            user.
-	 * @param project         name of project
-	 * @param exploratoryName name of exploratory.
-	 * @param dto             object of scheduler data.
-	 * @return The result of an update operation.
-	 */
-	public UpdateResult updateSchedulerDataForUserAndExploratory(String user, String project, String exploratoryName,
-																 SchedulerJobDTO dto) {
-		return updateOne(USER_INSTANCES,
-				exploratoryCondition(user, exploratoryName, project),
-				set(SCHEDULER_DATA, Objects.isNull(dto) ? null : convertToBson(dto)));
-	}
-
-	/**
-	 * Updates the requirement for reuploading key for single exploratory in Mongo database.
-	 *
-	 * @param user                user name.
-	 * @param project             project name
-	 * @param exploratoryName     exploratory's name
-	 * @param reuploadKeyRequired true/false.
-	 */
-	public void updateReuploadKeyForExploratory(String user, String project, String exploratoryName, boolean reuploadKeyRequired) {
-		updateOne(USER_INSTANCES,
-				exploratoryCondition(user, exploratoryName, project),
-				set(REUPLOAD_KEY_REQUIRED, reuploadKeyRequired));
-	}
-
-
-	/**
-	 * Updates the info of exploratory in Mongo database.
-	 *
-	 * @param dto object of exploratory status info.
-	 * @return The result of an update operation.
-	 */
-	@SuppressWarnings("serial")
-	public UpdateResult updateExploratoryFields(ExploratoryStatusDTO dto) {
-		Document values = new Document(STATUS, dto.getStatus()).append(UPTIME, dto.getUptime());
-		if (dto.getInstanceId() != null) {
-			values.append(INSTANCE_ID, dto.getInstanceId());
-		}
-		if (dto.getErrorMessage() != null) {
-			values.append(ERROR_MESSAGE, DateRemoverUtil.removeDateFormErrorMessage(dto.getErrorMessage()));
-		}
-		if (dto.getExploratoryId() != null) {
-			values.append(EXPLORATORY_ID, dto.getExploratoryId());
-		}
-
-		if (dto.getLastActivity() != null) {
-			values.append(EXPLORATORY_LAST_ACTIVITY, dto.getLastActivity());
-		}
-
-		if (dto.getResourceUrl() != null) {
-			values.append(EXPLORATORY_URL, dto.getResourceUrl().stream()
-					.map(url -> {
-								LinkedHashMap<String, String> map = new LinkedHashMap<>();
-								map.put(EXPLORATORY_URL_DESC, url.getDescription());
-								map.put(EXPLORATORY_URL_URL, url.getUrl());
-								return map;
-							}
-					).collect(Collectors.toList()));
-		} else if (dto.getPrivateIp() != null) {
-			UserInstanceDTO inst = fetchExploratoryFields(dto.getUser(), dto.getProject(), dto.getExploratoryName());
-			if (!inst.getPrivateIp().equals(dto.getPrivateIp()) && inst.getResourceUrl() != null) {
-				values.append(EXPLORATORY_URL, inst.getResourceUrl().stream()
-						.map(url -> replaceIp(dto.getPrivateIp(), inst, url))
-						.collect(Collectors.toList()));
-			}
-		}
-
-		if (dto.getPrivateIp() != null) {
-			values.append(EXPLORATORY_PRIVATE_IP, dto.getPrivateIp());
-		}
-		if (dto.getExploratoryUser() != null) {
-			values.append(EXPLORATORY_USER, dto.getExploratoryUser());
-		}
-		if (dto.getExploratoryPassword() != null) {
-			values.append(EXPLORATORY_PASS, dto.getExploratoryPassword());
-		}
-		if (dto.getConfig() != null) {
-			values.append(CLUSTER_CONFIG, dto.getConfig().stream().map(this::convertToBson).collect(toList()));
-		}
-		return updateOne(USER_INSTANCES,
-				exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
-				new Document(SET, values));
-	}
-
-	public void updateExploratoryIp(String user, String project, String ip, String exploratoryName) {
-
-		UserInstanceDTO inst = fetchExploratoryFields(user, project, exploratoryName);
-		if (!inst.getPrivateIp().equals(ip)) {
-			Document values = new Document();
-			values.append(EXPLORATORY_PRIVATE_IP, ip);
-			if (inst.getResourceUrl() != null) {
-				values.append(EXPLORATORY_URL, inst.getResourceUrl().stream()
-						.map(url -> replaceIp(ip, inst, url)
-						).collect(Collectors.toList()));
-			}
-
-			updateOne(USER_INSTANCES,
-					exploratoryCondition(user, exploratoryName, project),
-					new Document(SET, values));
-		}
-
-	}
-
-	@SuppressWarnings("unchecked")
-	public List<ClusterConfig> getClusterConfig(String user, String project, String exploratoryName) {
-		return findOne(USER_INSTANCES, and(exploratoryCondition(user, exploratoryName, project), notNull(CLUSTER_CONFIG)),
-				fields(include(CLUSTER_CONFIG), excludeId()))
-				.map(d -> convertFromDocument((List<Document>) d.get(CLUSTER_CONFIG),
-						new TypeReference<List<ClusterConfig>>() {
-						}))
-				.orElse(Collections.emptyList());
-	}
-
-	private Map<String, String> replaceIp(String ip, UserInstanceDTO inst, ResourceURL url) {
-		Map<String, String> map = new LinkedHashMap<>();
-		map.put(EXPLORATORY_URL_DESC, url.getDescription());
-		map.put(EXPLORATORY_URL_URL, url.getUrl().replace(inst.getPrivateIp(), ip));
-		return map;
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ExploratoryLibDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ExploratoryLibDAO.java
deleted file mode 100644
index 626e275..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ExploratoryLibDAO.java
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * 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.util.DateRemoverUtil;
-import com.epam.dlab.dto.exploratory.LibInstallDTO;
-import com.epam.dlab.dto.exploratory.LibInstallStatusDTO;
-import com.epam.dlab.dto.exploratory.LibStatus;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.model.ResourceType;
-import com.epam.dlab.model.library.Library;
-import com.mongodb.client.model.Projections;
-import org.apache.commons.lang3.StringUtils;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.COMPUTATIONAL_RESOURCES;
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.exploratoryCondition;
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.runningExploratoryAndComputationalCondition;
-import static com.epam.dlab.backendapi.dao.MongoCollections.USER_INSTANCES;
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Projections.elemMatch;
-import static com.mongodb.client.model.Projections.excludeId;
-import static com.mongodb.client.model.Projections.fields;
-import static com.mongodb.client.model.Projections.include;
-import static com.mongodb.client.model.Updates.push;
-
-/**
- * DAO for user libraries.
- */
-public class ExploratoryLibDAO extends BaseDAO {
-	public static final String EXPLORATORY_LIBS = "libs";
-	public static final String COMPUTATIONAL_LIBS = "computational_libs";
-	public static final String LIB_GROUP = "group";
-	public static final String LIB_NAME = "name";
-	public static final String LIB_VERSION = "version";
-	public static final String LIB_AVAILABLE_VERSION = "available_versions";
-	public static final String LIB_ADDED_PACKAGES = "add_pkgs";
-	private static final String LIB_INSTALL_DATE = "install_date";
-	private static final String LIB_ERROR_MESSAGE = "error_message";
-	private static final String COMPUTATIONAL_NAME_FIELD = "computational_name";
-
-	/**
-	 * Return condition for search library into exploratory data.
-	 *
-	 * @param libraryGroup the name of group.
-	 * @param libraryName  the name of library.
-	 */
-	private static Bson libraryConditionExploratory(String libraryGroup, String libraryName) {
-		return elemMatch(EXPLORATORY_LIBS,
-				libCondition(libraryGroup, libraryName));
-	}
-
-
-	/**
-	 * Return condition for search library into computational data.
-	 *
-	 * @param computationalName computational name
-	 * @param libraryGroup      the name of group.
-	 * @param libraryName       the name of library.
-	 */
-	private static Bson libraryConditionComputational(String computationalName, String libraryGroup,
-													  String libraryName) {
-		return elemMatch(COMPUTATIONAL_LIBS + "." + computationalName,
-				and(eq(LIB_GROUP, libraryGroup), eq(LIB_NAME, libraryName)));
-	}
-
-	/**
-	 * Return field filter for libraries properties in exploratory data.
-	 *
-	 * @param fieldName
-	 * @return
-	 */
-	private static String libraryFieldFilter(String fieldName) {
-		return EXPLORATORY_LIBS + FIELD_SET_DELIMETER + fieldName;
-	}
-
-
-	private static String computationalLibraryFieldFilter(String computational, String fieldName) {
-		return COMPUTATIONAL_LIBS + "." + computational + FIELD_SET_DELIMETER + fieldName;
-	}
-
-	private Document findLibraries(String user, String project, String exploratoryName, Bson include) {
-		Optional<Document> opt = findOne(USER_INSTANCES,
-				exploratoryCondition(user, exploratoryName, project),
-				fields(excludeId(), include));
-
-		return opt.orElseGet(Document::new);
-
-	}
-
-	public List<Library> getLibraries(String user, String project, String exploratoryName) {
-		final Document libsDocument = findAllLibraries(user, project, exploratoryName);
-		return Stream
-				.concat(
-						libraryStream(libsDocument, exploratoryName, EXPLORATORY_LIBS, ResourceType.EXPLORATORY),
-						computationalLibStream(libsDocument))
-				.collect(Collectors.toList());
-	}
-
-	public Document findAllLibraries(String user, String project, String exploratoryName) {
-		return findLibraries(user, project, exploratoryName, include(EXPLORATORY_LIBS, COMPUTATIONAL_LIBS,
-				COMPUTATIONAL_RESOURCES));
-	}
-
-	public Document findExploratoryLibraries(String user, String project, String exploratoryName) {
-		return findLibraries(user, project, exploratoryName, include(EXPLORATORY_LIBS));
-	}
-
-	public Document findComputationalLibraries(String user, String project, String exploratoryName, String computationalName) {
-		return findLibraries(user, project, exploratoryName, include(COMPUTATIONAL_LIBS + "." + computationalName));
-	}
-
-	@SuppressWarnings("unchecked")
-	public Library getLibrary(String user, String project, String exploratoryName, String libraryGroup, String libraryName) {
-		Optional<Document> userInstance = findOne(USER_INSTANCES,
-				and(exploratoryCondition(user, exploratoryName, project),
-						elemMatch(EXPLORATORY_LIBS,
-								and(eq(LIB_GROUP, libraryGroup), eq(LIB_NAME, libraryName))
-						)),
-				Projections.fields(excludeId(), Projections.include(EXPLORATORY_LIBS)));
-
-		if (userInstance.isPresent()) {
-			final Object exloratoryLibs = userInstance.get().get(EXPLORATORY_LIBS);
-			List<Document> libs = exloratoryLibs != null ? (List<Document>) exloratoryLibs : Collections.emptyList();
-			return libs.stream()
-					.filter(libraryPredicate(libraryGroup, libraryName))
-					.map(d -> convertFromDocument(d, Library.class))
-					.findAny().orElse(null);
-
-		}
-
-		return null;
-	}
-
-	@SuppressWarnings("unchecked")
-	public Library getLibrary(String user, String project, String exploratoryName, String computationalName,
-							  String libraryGroup, String libraryName) {
-		Optional<Document> libraryStatus = findOne(USER_INSTANCES,
-				and(runningExploratoryAndComputationalCondition(user, project, exploratoryName, computationalName),
-						libraryConditionComputational(computationalName, libraryGroup, libraryName)
-				),
-
-				Projections.fields(excludeId(),
-						Projections.include(
-								COMPUTATIONAL_LIBS + "." + computationalName + "." + STATUS,
-								COMPUTATIONAL_LIBS + "." + computationalName + "." + LIB_GROUP,
-								COMPUTATIONAL_LIBS + "." + computationalName + "." + LIB_NAME)
-				)
-		);
-
-		return libraryStatus.map(document -> ((List<Document>) (((Document) document.get(COMPUTATIONAL_LIBS)).get(computationalName)))
-				.stream()
-				.filter(libraryPredicate(libraryGroup, libraryName))
-				.map(l -> convertFromDocument(l, Library.class))
-				.findAny().orElse(null)).orElse(null);
-	}
-
-	private Predicate<Document> libraryPredicate(String libraryGroup, String libraryName) {
-		return l -> libraryGroup.equals(l.getString(LIB_GROUP))
-				&& libraryName.equals(l.getString(LIB_NAME));
-	}
-
-	/**
-	 * Add the user's library for exploratory into database.
-	 *
-	 * @param user            user name.
-	 * @param project         project name
-	 * @param exploratoryName name of exploratory.
-	 * @param library         library.
-	 * @return <b>true</b> if operation was successful, otherwise <b>false</b>.
-	 */
-	public boolean addLibrary(String user, String project, String exploratoryName, LibInstallDTO library, boolean reinstall) {
-		Optional<Document> opt = findOne(USER_INSTANCES,
-				and(exploratoryCondition(user, exploratoryName, project),
-						elemMatch(EXPLORATORY_LIBS,
-								and(eq(LIB_GROUP, library.getGroup()), eq(LIB_NAME, library.getName())))));
-		if (!opt.isPresent()) {
-			updateOne(USER_INSTANCES,
-					exploratoryCondition(user, exploratoryName, project),
-					push(EXPLORATORY_LIBS, convertToBson(library)));
-			return true;
-		} else {
-			Document values = addLibraryFields(library);
-			if (reinstall) {
-				values.append(libraryFieldFilter(LIB_INSTALL_DATE), null);
-				values.append(libraryFieldFilter(LIB_ERROR_MESSAGE), null);
-			}
-
-			updateOne(USER_INSTANCES, and(exploratoryCondition(user, exploratoryName, project),
-					elemMatch(EXPLORATORY_LIBS,
-							and(eq(LIB_GROUP, library.getGroup()), eq(LIB_NAME, library.getName())))),
-					new Document(SET, values));
-			return false;
-		}
-	}
-
-	/**
-	 * Add the user's library for exploratory into database.
-	 *
-	 * @param user              user name.
-	 * @param project           project name
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational.
-	 * @param library           library.
-	 * @return <b>true</b> if operation was successful, otherwise <b>false</b>.
-	 */
-	public boolean addLibrary(String user, String project, String exploratoryName, String computationalName,
-							  LibInstallDTO library, boolean reinstall) {
-
-		Optional<Document> opt = findOne(USER_INSTANCES,
-				and(runningExploratoryAndComputationalCondition(user, project, exploratoryName, computationalName),
-						eq(COMPUTATIONAL_LIBS + "." + computationalName + "." + LIB_GROUP, library.getGroup()),
-						eq(COMPUTATIONAL_LIBS + "." + computationalName + "." + LIB_NAME, library.getName())));
-
-		if (!opt.isPresent()) {
-			updateOne(USER_INSTANCES,
-					runningExploratoryAndComputationalCondition(user, project, exploratoryName, computationalName),
-					push(COMPUTATIONAL_LIBS + "." + computationalName, convertToBson(library)));
-			return true;
-		} else {
-			Document values = addComputationalLibraryFields(computationalName, library);
-			if (reinstall) {
-				values.append(computationalLibraryFieldFilter(computationalName, LIB_INSTALL_DATE), null);
-				values.append(computationalLibraryFieldFilter(computationalName, LIB_ERROR_MESSAGE), null);
-			}
-
-			updateOne(USER_INSTANCES, and(
-					exploratoryCondition(user, exploratoryName, project),
-					eq(COMPUTATIONAL_LIBS + "." + computationalName + "." + LIB_GROUP, library.getGroup()),
-					eq(COMPUTATIONAL_LIBS + "." + computationalName + "." + LIB_NAME, library.getName())),
-
-					new Document(SET, values));
-
-			return false;
-		}
-	}
-
-	/**
-	 * Updates the info about libraries for exploratory/computational in Mongo database.
-	 *
-	 * @param dto object of computational resource status.
-	 */
-	public void updateLibraryFields(LibInstallStatusDTO dto) {
-		if (dto.getLibs() == null) {
-			return;
-		}
-
-		if (StringUtils.isEmpty(dto.getComputationalName())) {
-			updateExploratoryLibraryFields(dto);
-		} else {
-			updateComputationalLibraryFields(dto);
-		}
-	}
-
-	private void updateExploratoryLibraryFields(LibInstallStatusDTO dto) {
-		for (LibInstallDTO lib : dto.getLibs()) {
-			try {
-				Document values = updateLibraryFields(lib, dto.getUptime());
-
-				updateOne(USER_INSTANCES,
-						and(exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
-								libraryConditionExploratory(lib.getGroup(), lib.getName())),
-						new Document(SET, values));
-			} catch (Exception e) {
-				throw new DlabException(String.format("Could not update library %s for %s",
-						lib, dto.getExploratoryName()), e);
-			}
-		}
-	}
-
-	private void updateComputationalLibraryFields(LibInstallStatusDTO dto) {
-		for (LibInstallDTO lib : dto.getLibs()) {
-			try {
-				Document values = updateComputationalLibraryFields(dto.getComputationalName(), lib, dto.getUptime());
-
-				updateOne(USER_INSTANCES,
-						and(exploratoryCondition(dto.getUser(), dto.getExploratoryName(), dto.getProject()),
-								elemMatch(COMPUTATIONAL_LIBS + "." + dto.getComputationalName(),
-										libCondition(lib.getGroup(), lib.getName()))),
-						new Document(SET, values));
-			} catch (Exception e) {
-				throw new DlabException(String.format("Could not update library %s for %s/%s",
-						lib, dto.getExploratoryName(), dto.getComputationalName()), e);
-			}
-		}
-	}
-
-	private static Bson libCondition(String group, String name) {
-		return and(eq(LIB_GROUP, group), eq(LIB_NAME, name));
-	}
-
-	private Document addLibraryFields(LibInstallDTO lib) {
-		Document values = new Document(libraryFieldFilter(STATUS), lib.getStatus());
-		if (lib.getVersion() != null) {
-			values.append(libraryFieldFilter(LIB_VERSION), lib.getVersion());
-		}
-
-		return values;
-	}
-
-	private Document updateLibraryFields(LibInstallDTO lib, Date uptime) {
-		Document values = new Document(libraryFieldFilter(STATUS), lib.getStatus());
-		if (lib.getVersion() != null) {
-			values.append(libraryFieldFilter(LIB_VERSION), lib.getVersion());
-		}
-		if (uptime != null) {
-			values.append(libraryFieldFilter(LIB_INSTALL_DATE), uptime);
-		}
-		if (lib.getAvailableVersions() != null) {
-			values.append(libraryFieldFilter(LIB_AVAILABLE_VERSION), lib.getAvailableVersions());
-		}
-		if (lib.getAddedPackages() != null) {
-			values.append(libraryFieldFilter(LIB_ADDED_PACKAGES), lib.getAddedPackages());
-		}
-		if (lib.getErrorMessage() != null) {
-			values.append(libraryFieldFilter(LIB_ERROR_MESSAGE),
-					DateRemoverUtil.removeDateFormErrorMessage(lib.getErrorMessage()));
-		}
-
-		return values;
-	}
-
-	private Document addComputationalLibraryFields(String computational, LibInstallDTO lib) {
-		Document values = new Document(computationalLibraryFieldFilter(computational, STATUS), lib.getStatus());
-		if (lib.getVersion() != null) {
-			values.append(computationalLibraryFieldFilter(computational, LIB_VERSION), lib.getVersion());
-		}
-
-		return values;
-	}
-
-	private Document updateComputationalLibraryFields(String computational, LibInstallDTO lib, Date uptime) {
-		Document values = new Document(computationalLibraryFieldFilter(computational, STATUS), lib.getStatus());
-		if (lib.getVersion() != null) {
-			values.append(computationalLibraryFieldFilter(computational, LIB_VERSION), lib.getVersion());
-		}
-		if (uptime != null) {
-			values.append(computationalLibraryFieldFilter(computational, LIB_INSTALL_DATE), uptime);
-		}
-		if (lib.getAvailableVersions() != null) {
-			values.append(computationalLibraryFieldFilter(computational, LIB_AVAILABLE_VERSION), lib.getAvailableVersions());
-		}
-		if (lib.getAddedPackages() != null) {
-			values.append(computationalLibraryFieldFilter(computational, LIB_ADDED_PACKAGES), lib.getAddedPackages());
-		}
-		if (lib.getErrorMessage() != null) {
-			values.append(computationalLibraryFieldFilter(computational, LIB_ERROR_MESSAGE),
-					DateRemoverUtil.removeDateFormErrorMessage(lib.getErrorMessage()));
-		}
-
-		return values;
-	}
-
-	@SuppressWarnings("unchecked")
-	private Stream<Library> computationalLibStream(Document libsDocument) {
-		return ((List<Document>) libsDocument.getOrDefault(COMPUTATIONAL_RESOURCES, Collections.emptyList()))
-				.stream()
-				.map(d -> d.getString(COMPUTATIONAL_NAME_FIELD))
-				.flatMap(compName -> libraryStream(
-						(Document) libsDocument.getOrDefault(COMPUTATIONAL_LIBS, new Document()),
-						compName,
-						compName, ResourceType.COMPUTATIONAL));
-	}
-
-	@SuppressWarnings("unchecked")
-	private Stream<Library> libraryStream(Document libsDocument, String resourceName, String libFieldName,
-										  ResourceType libType) {
-		return ((List<Document>) libsDocument.getOrDefault(libFieldName, Collections.emptyList()))
-				.stream()
-				.map(d -> convertFromDocument(d, Library.class))
-				.filter(library -> !Arrays.asList(LibStatus.INVALID_VERSION, LibStatus.INVALID_NAME).contains(library.getStatus()))
-				.peek(l -> l.withType(libType).withResourceName(resourceName));
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/GitCredsDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/GitCredsDAO.java
deleted file mode 100644
index 817f127..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/GitCredsDAO.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.dto.exploratory.ExploratoryGitCreds;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsDTO;
-import org.bson.Document;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-import static com.epam.dlab.backendapi.dao.MongoCollections.GIT_CREDS;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Projections.*;
-
-/** DAO for user exploratory.
- */
-public class GitCredsDAO extends BaseDAO {
-	private static final String FIELD_GIT_CREDS = "git_creds";
-
-    /** Find and return the list of GIT credentials for user. 
-     * @param user name.
-	 * @return GIT credentials DTO
-     */
-    public ExploratoryGitCredsDTO findGitCreds(String user) {
-    	return findGitCreds(user, false);
-    }
-
-    /** Find and return the list of GIT credentials for user. 
-     * @param user name.
-     * @param clearPassword clear user password if set to <b>true</b>.
-	 * @return GIT credentials DTO
-     */
-    public ExploratoryGitCredsDTO findGitCreds(String user, boolean clearPassword) {
-    	Optional<ExploratoryGitCredsDTO> opt = findOne(GIT_CREDS,
-    													eq(ID, user),
-    													fields(include(FIELD_GIT_CREDS), excludeId()),
-    													ExploratoryGitCredsDTO.class);
-		ExploratoryGitCredsDTO creds = (opt.orElseGet(ExploratoryGitCredsDTO::new));
-    	List<ExploratoryGitCreds> list = creds.getGitCreds();
-    	if (clearPassword && list != null) {
-    		for (ExploratoryGitCreds cred : list) {
-				cred.setPassword(null);
-			}
-    	}
-    	
-    	return creds;
-    }
-
-    /** Update the GIT credentials for user.
-     * @param user name.
-     * @param dto GIT credentials.
-     */
-	public void updateGitCreds(String user, ExploratoryGitCredsDTO dto) {
-    	List<ExploratoryGitCreds> list = findGitCreds(user).getGitCreds();
-    	if (list != null && dto.getGitCreds() != null) {
-        	Collections.sort(dto.getGitCreds());
-    		// Restore passwords from Mongo DB.
-    		for (ExploratoryGitCreds cred : dto.getGitCreds()) {
-    			if (cred.getPassword() == null) {
-    				int index = Collections.binarySearch(list, cred);
-    				if (index >= 0) {
-    					cred.setPassword(list.get(index).getPassword());
-    				}
-    			}
-			}
-    	}
-
-		Document d = new Document(SET, convertToBson(dto).append(ID, user));
-		updateOne(GIT_CREDS, eq(ID, user), d, true);
-    }
-}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ImageExploratoryDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ImageExploratoryDAO.java
deleted file mode 100644
index 9bab74d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ImageExploratoryDAO.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.resources.dto.ImageInfoRecord;
-import com.epam.dlab.dto.exploratory.ImageStatus;
-import com.epam.dlab.dto.exploratory.LibStatus;
-import com.epam.dlab.model.exploratory.Image;
-import com.epam.dlab.model.library.Library;
-
-import java.util.List;
-import java.util.Optional;
-
-public interface ImageExploratoryDAO {
-
-	boolean exist(String image, String project);
-
-	void save(Image image);
-
-	void updateImageFields(Image image);
-
-	List<ImageInfoRecord> getImages(String user, String dockerImage, String project, String endpoint, ImageStatus... statuses);
-
-	List<ImageInfoRecord> getImagesForProject(String project);
-
-	Optional<ImageInfoRecord> getImage(String user, String name, String project, String endpoint);
-
-	List<Library> getLibraries(String user, String imageFullName, String project, String endpoint, LibStatus status);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ImageExploratoryDAOImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ImageExploratoryDAOImpl.java
deleted file mode 100644
index 7aadcc4..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ImageExploratoryDAOImpl.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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.resources.dto.ImageInfoRecord;
-import com.epam.dlab.dto.exploratory.ImageStatus;
-import com.epam.dlab.dto.exploratory.LibStatus;
-import com.epam.dlab.model.exploratory.Image;
-import com.epam.dlab.model.library.Library;
-import com.google.inject.Singleton;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.in;
-import static com.mongodb.client.model.Projections.elemMatch;
-import static com.mongodb.client.model.Projections.excludeId;
-import static com.mongodb.client.model.Projections.fields;
-import static com.mongodb.client.model.Projections.include;
-
-@Singleton
-public class ImageExploratoryDAOImpl extends BaseDAO implements ImageExploratoryDAO {
-
-	private static final String LIBRARIES = "libraries";
-	private static final String IMAGE_NAME = "name";
-	private static final String IMAGE_APPLICATION = "application";
-	private static final String IMAGE_FULL_NAME = "fullName";
-	private static final String EXTERNAL_NAME = "externalName";
-	private static final String DOCKER_IMAGE = "dockerImage";
-	private static final String PROJECT = "project";
-	private static final String ENDPOINT = "endpoint";
-
-	@Override
-	public boolean exist(String image, String project) {
-		return findOne(MongoCollections.IMAGES, imageProjectCondition(image, project)).isPresent();
-	}
-
-	@Override
-	public void save(Image image) {
-		insertOne(MongoCollections.IMAGES, image);
-	}
-
-	@Override
-	public void updateImageFields(Image image) {
-		final Bson condition = userImageCondition(image.getUser(), image.getName(), image.getProject(), image.getEndpoint());
-		final Document updatedFields = getUpdatedFields(image);
-		updateOne(MongoCollections.IMAGES, condition, new Document(SET, updatedFields));
-	}
-
-	@Override
-	public List<ImageInfoRecord> getImages(String user, String dockerImage, String project, String endpoint, ImageStatus... statuses) {
-		return find(MongoCollections.IMAGES,
-				userImagesCondition(user, dockerImage, project, endpoint, statuses),
-				ImageInfoRecord.class);
-	}
-
-	@Override
-	public List<ImageInfoRecord> getImagesForProject(String project) {
-		return find(MongoCollections.IMAGES,
-				eq(PROJECT, project),
-				ImageInfoRecord.class);
-	}
-
-	@Override
-	public Optional<ImageInfoRecord> getImage(String user, String name, String project, String endpoint) {
-		return findOne(MongoCollections.IMAGES, userImageCondition(user, name, project, endpoint), ImageInfoRecord.class);
-	}
-
-	@Override
-	@SuppressWarnings("unchecked")
-	public List<Library> getLibraries(String user, String imageFullName, String project, String endpoint, LibStatus status) {
-		return ((List<Document>) libDocument(user, imageFullName, project, endpoint, status)
-				.orElse(emptyLibrariesDocument()).get(LIBRARIES))
-				.stream()
-				.map(d -> convertFromDocument(d, Library.class))
-				.collect(Collectors.toList());
-	}
-
-	private Optional<Document> libDocument(String user, String imageFullName, String project, String endpoint,
-										   LibStatus status) {
-		return findOne(MongoCollections.IMAGES,
-				imageLibraryCondition(user, imageFullName, project, endpoint, status),
-				fields(include(LIBRARIES), excludeId()));
-	}
-
-	private Document emptyLibrariesDocument() {
-		return new Document(LIBRARIES, Collections.emptyList());
-	}
-
-	private Bson imageLibraryCondition(String user, String imageFullName, String project, String endpoint,
-									   LibStatus status) {
-		return and(eq(USER, user), eq(IMAGE_NAME, imageFullName), eq(PROJECT, project), eq(ENDPOINT, endpoint),
-				elemMatch(LIBRARIES, eq(STATUS, status.name())));
-	}
-
-	private Bson userImagesCondition(String user, String dockerImage, String project, String endpoint, ImageStatus... statuses) {
-		final Bson userImagesCondition = userImagesCondition(user, project, endpoint, statuses);
-		if (Objects.nonNull(dockerImage)) {
-			return and(userImagesCondition, eq(DOCKER_IMAGE, dockerImage));
-		} else {
-			return userImagesCondition;
-		}
-
-	}
-
-	private Bson userImagesCondition(String user, String project, String endpoint, ImageStatus... statuses) {
-
-		final List<String> statusList = Arrays
-				.stream(statuses)
-				.map(ImageStatus::name)
-				.collect(Collectors.toList());
-		return and(eq(USER, user), in(STATUS, statusList), eq(PROJECT, project), eq(ENDPOINT, endpoint));
-	}
-
-
-	private Bson userImageCondition(String user, String imageName, String project, String endpoint) {
-		return and(eq(USER, user), eq(IMAGE_NAME, imageName), eq(PROJECT, project), eq(ENDPOINT, endpoint));
-	}
-
-	private Bson imageProjectCondition(String image, String project) {
-		return and(eq(IMAGE_NAME, image), eq(PROJECT, project));
-	}
-
-	private Document getUpdatedFields(Image image) {
-		return new Document(STATUS, image.getStatus().toString())
-				.append(IMAGE_FULL_NAME, image.getFullName())
-				.append(IMAGE_APPLICATION, image.getApplication())
-				.append(EXTERNAL_NAME, image.getExternalName());
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/IndexCreator.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/IndexCreator.java
deleted file mode 100644
index 4145d70..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/IndexCreator.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.mongodb.client.model.IndexOptions;
-import com.mongodb.client.model.Indexes;
-import io.dropwizard.lifecycle.Managed;
-
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.EXPLORATORY_NAME;
-import static com.epam.dlab.backendapi.dao.MongoCollections.USER_INSTANCES;
-
-/** Creates the indexes for mongo collections. */
-public class IndexCreator extends BaseDAO implements Managed {
-    private static final String PROJECT_FIELD = "project";
-    @Override
-	public void start() {
-        mongoService.getCollection(USER_INSTANCES)
-                .createIndex(Indexes.ascending(USER, EXPLORATORY_NAME, PROJECT_FIELD), new IndexOptions().unique(true));
-    }
-
-    @Override
-	public void stop() {
-		//Add some functionality if necessary
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/MongoCollections.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/MongoCollections.java
deleted file mode 100644
index 59343c9..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/MongoCollections.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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;
-
-/** Names of Mongo collections. */
-public class MongoCollections {
-	/** Environment settings. */
-	public static final String SETTINGS = "settings";
-    /** Attempts of the user login into DLab. */
-	static final String LOGIN_ATTEMPTS = "loginAttempts";
-    /** Attempts the actions of docker. */
-	static final String DOCKER_ATTEMPTS = "dockerAttempts";
-    /** User keys and credentials. */
-	static final String USER_KEYS = "userKeys";
-    /** User AWS credentials. */
-	public static final String USER_EDGE = "userCloudCredentials";
-    /** Instances of user. */
-	public static final String USER_INSTANCES = "userInstances";
-    /** Name of shapes. */
-	public static final String SHAPES = "shapes";
-	static final String USER_SETTINGS = "userSettings";
-    /* Billing data. */
-	public static final String BILLING = "billing";
-    /** User roles. */
-	static final String ROLES = "roles";
-    /** GIT credentials of user. */
-	public static final String GIT_CREDS = "gitCreds";
-    /** RequestId */
-	static final String REQUEST_ID = "requestId";
-    /** Images */
-	public static final String IMAGES = "images";
-	/**
-	 * Backup
-	 */
-	public static final String BACKUPS = "backup";
-
-	public static final String USER_GROUPS = "userGroups";
-
-	private MongoCollections() {
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/MongoSetting.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/MongoSetting.java
deleted file mode 100644
index bfa4e84..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/MongoSetting.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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;
-
-/**
- * Name of fields in the Mongo collection {@link MongoCollections#SETTINGS}.
- */
-public enum MongoSetting {
-
-	// General properties
-	/**
-	 * Base name of service.
-	 */
-	SERIVICE_BASE_NAME("conf_service_base_name"),
-	/**
-	 * Name of directory for user key.
-	 */
-	CONF_KEY_DIRECTORY("conf_key_dir"),
-	/**
-	 * Name of resource id.
-	 */
-	CONF_TAG_RESOURCE_ID("conf_tag_resource_id"),
-	/**
-	 * Name of OS family.
-	 */
-	CONF_OS_FAMILY("conf_os_family"),
-
-	CONF_MAX_BUDGET("conf_max_budget"),
-	SSN_STORAGE_ACCOUNT_TAG_NAME("ssn_storage_account_tag_name"),
-	SHARED_STORAGE_ACCOUNT_TAG_NAME("shared_storage_account_tag_name"),
-
-	LDAP_HOSTNAME("ldap_hostname"),
-	LDAP_DN("ldap_dn"),
-	LDAP_OU("ldap_ou"),
-	LDAP_USER("ldap_service_username"),
-	LDAP_PASSWORD("ldap_service_password"),
-
-	PEERING_ID("peering_id"),
-
-
-	// AWS Related properties
-	/**
-	 * Name of AWS region.
-	 */
-	AWS_REGION("aws_region"),
-	/**
-	 * Id of security group.
-	 */
-	AWS_SECURITY_GROUPS("aws_security_groups_ids"),
-	/**
-	 * Id of virtual private cloud for AWS account.
-	 */
-	AWS_VPC_ID("aws_vpc_id"),
-	/**
-	 * Id of virtual private cloud subnet for AWS account.
-	 */
-	AWS_SUBNET_ID("aws_subnet_id"),
-	AWS_NOTEBOOK_VPC_ID("aws_notebook_vpc_id"),
-	AWS_NOTEBOOK_SUBNET_ID("aws_notebook_subnet_id"),
-	AWS_ZONE("aws_zone"),
-
-
-	// Azure related properties
-	AZURE_REGION("azure_region"),
-	AZURE_RESOURCE_GROUP_NAME("azure_resource_group_name"),
-	AZURE_SUBNET_NAME("azure_subnet_name"),
-	AZURE_VPC_NAME("azure_vpc_name"),
-	AZURE_SECURITY_GROUP_NAME("azure_security_group_name"),
-	AZURE_EDGE_INSTANCE_SIZE("edge_instance_size"),
-	SSN_INSTANCE_SIZE("ssn_instance_size"),
-	AZURE_DATA_LAKE_NAME_TAG("datalake_tag_name"),
-	AZURE_DATA_LAKE_CLIENT_ID("azure_client_id"),
-
-	// GCP related properties
-	GCP_REGION("gcp_region"),
-	GCP_ZONE("gcp_zone"),
-	GCP_SUBNET_NAME("gcp_subnet_name"),
-	GCP_PROJECT_ID("gcp_project_id"),
-	GCP_VPC_NAME("gcp_vpc_name");
-
-	private String id;
-
-	MongoSetting(String id) {
-		this.id = id;
-	}
-
-	public String getId() {
-		return id;
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAO.java
deleted file mode 100644
index 24850cb..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAO.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-public interface ProjectDAO {
-	List<ProjectDTO> getProjects();
-
-	List<ProjectDTO> getProjectsWithEndpointStatusNotIn(UserInstanceStatus... statuses);
-
-	List<ProjectDTO> getUserProjects(UserInfo userInfo, boolean active);
-
-	void create(ProjectDTO projectDTO);
-
-	void updateStatus(String projectName, ProjectDTO.Status status);
-
-	void updateEdgeStatus(String projectName, String endpoint, UserInstanceStatus status);
-
-	void updateEdgeInfo(String projectName, String endpointName, EdgeInfo edgeInfo);
-
-	Optional<ProjectDTO> get(String name);
-
-	List<ProjectDTO> getProjectsByEndpoint(String endpointName);
-
-	boolean update(ProjectDTO projectDTO);
-
-	void remove(String name);
-
-	Optional<Integer> getAllowedBudget(String project);
-
-	void updateBudget(String project, Integer budget, boolean monthlyBudget);
-
-	boolean isAnyProjectAssigned(Set<String> groups);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAOImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAOImpl.java
deleted file mode 100644
index f08e3a3..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAOImpl.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.BudgetDTO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-import com.google.common.collect.Iterables;
-import com.google.inject.Inject;
-import com.mongodb.BasicDBObject;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.elemMatch;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.in;
-import static com.mongodb.client.model.Filters.not;
-
-public class ProjectDAOImpl extends BaseDAO implements ProjectDAO {
-
-	private static final String PROJECTS_COLLECTION = "Projects";
-	private static final String GROUPS = "groups";
-	private static final String ENDPOINTS = "endpoints";
-	private static final String STATUS_FIELD = "status";
-	private static final String BUDGET_FIELD = "budget";
-	private static final String VALUE_FIELD = "value";
-	private static final String MONTHLY_BUDGET_FIELD = "monthlyBudget";
-	private static final String SHARED_IMAGE_FIELD = "sharedImageEnabled";
-	private static final String ENDPOINT_STATUS_FIELD = "endpoints." + STATUS_FIELD;
-	private static final String EDGE_INFO_FIELD = "edgeInfo";
-	private static final String ENDPOINT_FIELD = "endpoints.$.";
-	private static final String ANYUSER = Pattern.quote("$anyuser");
-
-	private final UserGroupDAO userGroupDao;
-
-	@Inject
-	public ProjectDAOImpl(UserGroupDAO userGroupDao) {
-		this.userGroupDao = userGroupDao;
-	}
-
-
-	@Override
-	public List<ProjectDTO> getProjects() {
-		return find(PROJECTS_COLLECTION, ProjectDTO.class);
-	}
-
-	@Override
-	public List<ProjectDTO> getProjectsWithEndpointStatusNotIn(UserInstanceStatus... statuses) {
-		final List<String> statusList =
-				Arrays.stream(statuses)
-						.map(UserInstanceStatus::name)
-						.collect(Collectors.toList());
-
-		return find(PROJECTS_COLLECTION, not(in(ENDPOINT_STATUS_FIELD, statusList)), ProjectDTO.class);
-	}
-
-	@Override
-	public List<ProjectDTO> getUserProjects(UserInfo userInfo, boolean active) {
-		Stream<String> userGroups = userGroupDao.getUserGroups(userInfo.getName()).stream();
-		Stream<String> roles = userInfo.getRoles().stream();
-		final Set<String> groups = Stream.concat(userGroups, roles)
-				.collect(Collectors.toSet());
-		return find(PROJECTS_COLLECTION, userProjectCondition(groups, active), ProjectDTO.class);
-	}
-
-	@Override
-	public void create(ProjectDTO projectDTO) {
-		insertOne(PROJECTS_COLLECTION, projectDTO);
-	}
-
-	@Override
-	public void updateStatus(String projectName, ProjectDTO.Status status) {
-		updateOne(PROJECTS_COLLECTION, projectCondition(projectName),
-				new Document(SET, new Document(STATUS_FIELD, status.toString())));
-	}
-
-	@Override
-	public void updateEdgeStatus(String projectName, String endpoint, UserInstanceStatus status) {
-		BasicDBObject dbObject = new BasicDBObject();
-		dbObject.put(ENDPOINT_FIELD + STATUS_FIELD, status.name());
-		updateOne(PROJECTS_COLLECTION, projectAndEndpointCondition(projectName,
-				endpoint), new Document(SET, dbObject));
-	}
-
-	@Override
-	public void updateEdgeInfo(String projectName, String endpointName, EdgeInfo edgeInfo) {
-		BasicDBObject dbObject = new BasicDBObject();
-		dbObject.put(ENDPOINT_FIELD + STATUS_FIELD, UserInstanceStatus.RUNNING.name());
-		dbObject.put(ENDPOINT_FIELD + EDGE_INFO_FIELD, convertToBson(edgeInfo));
-		updateOne(PROJECTS_COLLECTION, projectAndEndpointCondition(projectName, endpointName), new Document(SET,
-				dbObject));
-	}
-
-	@Override
-	public Optional<ProjectDTO> get(String name) {
-		return findOne(PROJECTS_COLLECTION, projectCondition(name), ProjectDTO.class);
-	}
-
-	@Override
-	public List<ProjectDTO> getProjectsByEndpoint(String endpointName) {
-		return find(PROJECTS_COLLECTION, elemMatch(ENDPOINTS, eq("name", endpointName)), ProjectDTO.class);
-	}
-
-	@Override
-	public boolean update(ProjectDTO projectDTO) {
-		BasicDBObject updateProject = new BasicDBObject();
-		updateProject.put(GROUPS, projectDTO.getGroups());
-		updateProject.put(ENDPOINTS,
-				projectDTO.getEndpoints().stream().map(this::convertToBson).collect(Collectors.toList()));
-		updateProject.put(SHARED_IMAGE_FIELD, projectDTO.isSharedImageEnabled());
-		return updateOne(PROJECTS_COLLECTION, projectCondition(projectDTO.getName()),
-				new Document(SET, updateProject)).getMatchedCount() > 0L;
-	}
-
-	@Override
-	public void remove(String name) {
-		deleteOne(PROJECTS_COLLECTION, projectCondition(name));
-	}
-
-	@Override
-	public Optional<Integer> getAllowedBudget(String project) {
-		return get(project)
-				.flatMap(p -> Optional.ofNullable(p.getBudget())
-						.map(BudgetDTO::getValue));
-	}
-
-	@Override
-	public void updateBudget(String project, Integer budget, boolean monthlyBudget) {
-		BasicDBObject updateBudget = new BasicDBObject();
-		updateBudget.put(VALUE_FIELD, budget);
-		updateBudget.put(MONTHLY_BUDGET_FIELD, monthlyBudget);
-		updateOne(PROJECTS_COLLECTION, projectCondition(project), new Document(SET, new Document(BUDGET_FIELD, updateBudget)));
-	}
-
-	@Override
-	public boolean isAnyProjectAssigned(Set<String> groups) {
-		final String groupsRegex = !groups.isEmpty() ? String.join("|", groups) + "|" + ANYUSER : ANYUSER;
-		return !Iterables.isEmpty(find(PROJECTS_COLLECTION, elemMatch(GROUPS, regexCaseInsensitive(groupsRegex))));
-	}
-
-	private Bson projectCondition(String name) {
-		return eq("name", name);
-	}
-
-	private Bson userProjectCondition(Set<String> groups, boolean active) {
-		final String groupsRegex = !groups.isEmpty() ? String.join("|", groups) + "|" + ANYUSER : ANYUSER;
-		if (active) {
-			return and(elemMatch(GROUPS, regexCaseInsensitive(groupsRegex)),
-					eq(ENDPOINT_STATUS_FIELD, UserInstanceStatus.RUNNING.name()));
-		}
-		return elemMatch(GROUPS, regexCaseInsensitive(groupsRegex));
-	}
-
-	private Bson projectAndEndpointCondition(String projectName, String endpointName) {
-		return and(eq("name", projectName), eq("endpoints.name", endpointName));
-	}
-
-	private Document regexCaseInsensitive(String values) {
-		return new Document("$regex",
-				"^(" + values + ")$").append("$options", "i");
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/RequestIdDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/RequestIdDAO.java
deleted file mode 100644
index f90d2e1..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/RequestIdDAO.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.RequestIdDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.mongodb.client.model.Updates;
-import com.mongodb.client.result.DeleteResult;
-import org.bson.Document;
-
-import java.util.Date;
-import java.util.Optional;
-
-import static com.epam.dlab.backendapi.dao.MongoCollections.REQUEST_ID;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.lt;
-
-/** DAO for request id.
- */
-public class RequestIdDAO extends BaseDAO {
-    private static final String EXPIRATION_TIME = "expirationTime";
-
-	public RequestIdDTO get(String id) {
-		Optional<RequestIdDTO> opt = findOne(REQUEST_ID, eq(ID, id), RequestIdDTO.class);
-		if (!opt.isPresent()) {
-			throw new DlabException("Request id " + id + " not found.");
-		}
-		return opt.get();
-    }
-
-	public void put(RequestIdDTO requestId) {
-		getCollection(REQUEST_ID)
-			.insertOne(convertToBson(requestId));
-    }
-
-	public void delete(String id) {
-		getCollection(REQUEST_ID).deleteOne(eq(ID, id));
-    }
-
-	public void resetExpirationTime() {
-		Date time = new Date();
-		getCollection(REQUEST_ID).updateMany(new Document(), Updates.set(EXPIRATION_TIME, time));
-    }
-
-	public long removeExpired() {
-		DeleteResult result = getCollection(REQUEST_ID)
-								.deleteMany(lt(EXPIRATION_TIME, new Date()));
-		return result.getDeletedCount();
-    }
-}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SchedulerJobDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SchedulerJobDAO.java
deleted file mode 100644
index fc292dd..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SchedulerJobDAO.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * 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.dto.SchedulerJobDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.model.scheduler.SchedulerJobData;
-import com.google.inject.Singleton;
-import com.mongodb.client.FindIterable;
-import com.mongodb.client.model.Filters;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static com.epam.dlab.backendapi.dao.ComputationalDAO.COMPUTATIONAL_NAME;
-import static com.epam.dlab.backendapi.dao.ComputationalDAO.IMAGE;
-import static com.epam.dlab.backendapi.dao.ComputationalDAO.PROJECT;
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.COMPUTATIONAL_RESOURCES;
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.EXPLORATORY_NAME;
-import static com.epam.dlab.backendapi.dao.ExploratoryDAO.exploratoryCondition;
-import static com.epam.dlab.backendapi.dao.MongoCollections.USER_INSTANCES;
-import static com.epam.dlab.dto.base.DataEngineType.fromDockerImageName;
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.exists;
-import static com.mongodb.client.model.Filters.in;
-import static com.mongodb.client.model.Filters.lte;
-import static com.mongodb.client.model.Filters.ne;
-import static com.mongodb.client.model.Filters.or;
-import static com.mongodb.client.model.Projections.excludeId;
-import static com.mongodb.client.model.Projections.fields;
-import static com.mongodb.client.model.Projections.include;
-import static java.util.stream.Collectors.toList;
-
-/**
- * DAO for user's scheduler jobs.
- */
-@Slf4j
-@Singleton
-public class SchedulerJobDAO extends BaseDAO {
-
-	static final String SCHEDULER_DATA = "scheduler_data";
-	private static final String CONSIDER_INACTIVITY_FLAG = SCHEDULER_DATA + ".consider_inactivity";
-	public static final String TIMEZONE_PREFIX = "UTC";
-	private static final String LAST_ACTIVITY = "last_activity";
-	private static final String CHECK_INACTIVITY_REQUIRED = "check_inactivity_required";
-	private static final String CHECK_INACTIVITY_FLAG = SCHEDULER_DATA + "." + CHECK_INACTIVITY_REQUIRED;
-
-
-	public SchedulerJobDAO() {
-		log.info("{} is initialized", getClass().getSimpleName());
-	}
-
-	/**
-	 * Returns condition for search scheduler for exploratory which is not null.
-	 *
-	 * @return Bson condition.
-	 */
-	private Bson schedulerNotNullCondition() {
-		return and(exists(SCHEDULER_DATA), ne(SCHEDULER_DATA, null));
-	}
-
-	/**
-	 * Finds and returns the info of user's single scheduler job by exploratory name.
-	 *
-	 * @param user            user name.
-	 * @param project         project name
-	 * @param exploratoryName the name of exploratory.
-	 * @return scheduler job data.
-	 */
-	public Optional<SchedulerJobDTO> fetchSingleSchedulerJobByUserAndExploratory(String user, String project, String exploratoryName) {
-		return findOne(USER_INSTANCES,
-				and(exploratoryCondition(user, exploratoryName, project), schedulerNotNullCondition()),
-				fields(include(SCHEDULER_DATA), excludeId()))
-				.map(d -> convertFromDocument((Document) d.get(SCHEDULER_DATA), SchedulerJobDTO.class));
-	}
-
-	/**
-	 * Finds and returns the info of user's single scheduler job for computational resource.
-	 *
-	 * @param user              user name.
-	 * @param project           project name
-	 * @param exploratoryName   the name of exploratory.
-	 * @param computationalName the name of computational resource.
-	 * @return scheduler job data.
-	 */
-
-	@SuppressWarnings("unchecked")
-	public Optional<SchedulerJobDTO> fetchSingleSchedulerJobForCluster(String user, String project, String exploratoryName,
-																	   String computationalName) {
-		return findOne(USER_INSTANCES,
-				exploratoryCondition(user, exploratoryName, project),
-				fields(include(COMPUTATIONAL_RESOURCES), excludeId()))
-				.map(d -> (List<Document>) d.get(COMPUTATIONAL_RESOURCES))
-				.map(list -> list.stream().filter(d -> d.getString(COMPUTATIONAL_NAME).equals(computationalName))
-						.findAny().orElse(new Document()))
-				.map(d -> (Document) d.get(SCHEDULER_DATA))
-				.map(d -> convertFromDocument(d, SchedulerJobDTO.class));
-	}
-
-	/**
-	 * Finds and returns the list of all scheduler jobs for starting/stopping/terminating exploratories regarding to
-	 * parameter passed.
-	 *
-	 * @param status 'running' value for starting exploratory, 'stopped' - for stopping and 'terminated' -
-	 *               for
-	 *               terminating.
-	 * @return list of scheduler jobs.
-	 */
-	public List<SchedulerJobData> getExploratorySchedulerDataWithStatus(UserInstanceStatus status) {
-		FindIterable<Document> userInstances = userInstancesWithScheduler(eq(STATUS, status.toString()));
-
-		return stream(userInstances).map(d -> convertFromDocument(d, SchedulerJobData.class))
-				.collect(toList());
-	}
-
-	public List<SchedulerJobData> getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(UserInstanceStatus status,
-																								  Date lastActivity) {
-		return stream(find(USER_INSTANCES,
-				and(
-						eq(STATUS, status.toString()),
-						schedulerNotNullCondition(),
-						or(and(eq(CONSIDER_INACTIVITY_FLAG, true),
-								or(eq(COMPUTATIONAL_RESOURCES, Collections.emptyList()),
-										and(ne(COMPUTATIONAL_RESOURCES, Collections.emptyList()),
-												Filters.elemMatch(COMPUTATIONAL_RESOURCES,
-														lte(LAST_ACTIVITY, lastActivity))))),
-								eq(CONSIDER_INACTIVITY_FLAG, false)
-						)
-				),
-				fields(excludeId(), include(USER, PROJECT, EXPLORATORY_NAME, SCHEDULER_DATA))))
-				.map(d -> convertFromDocument(d, SchedulerJobData.class))
-				.collect(toList());
-	}
-
-	public List<SchedulerJobData> getExploratorySchedulerDataWithOneOfStatus(UserInstanceStatus... statuses) {
-		FindIterable<Document> userInstances = userInstancesWithScheduler(in(STATUS,
-				Arrays.stream(statuses).map(UserInstanceStatus::toString).collect(toList())));
-
-		return stream(userInstances).map(d -> convertFromDocument(d, SchedulerJobData.class))
-				.collect(toList());
-	}
-
-	public List<SchedulerJobData> getComputationalSchedulerDataWithOneOfStatus(UserInstanceStatus exploratoryStatus,
-																			   DataEngineType dataEngineType,
-																			   UserInstanceStatus... statuses) {
-		return stream(computationalResourcesWithScheduler(exploratoryStatus))
-				.map(doc -> computationalSchedulerDataStream(doc, dataEngineType, statuses))
-				.flatMap(Function.identity())
-				.collect(toList());
-	}
-
-	public List<SchedulerJobData> getComputationalSchedulerDataWithOneOfStatus(UserInstanceStatus exploratoryStatus,
-																			   UserInstanceStatus... statuses) {
-		return stream(computationalResourcesWithScheduler(exploratoryStatus))
-				.map(doc -> computationalSchedulerData(doc, statuses).map(compResource -> toSchedulerData(doc,
-						compResource)))
-				.flatMap(Function.identity())
-				.collect(toList());
-	}
-
-	private FindIterable<Document> computationalResourcesWithScheduler(UserInstanceStatus exploratoryStatus) {
-		final Bson computationalSchedulerCondition = Filters.elemMatch(COMPUTATIONAL_RESOURCES,
-				and(schedulerNotNullCondition()));
-		return find(USER_INSTANCES,
-				and(eq(STATUS, exploratoryStatus.toString()), computationalSchedulerCondition),
-				fields(excludeId(), include(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_RESOURCES)));
-	}
-
-	public void removeScheduler(String user, String exploratory) {
-		updateOne(USER_INSTANCES, and(eq(USER, user), eq(EXPLORATORY_NAME, exploratory)),
-				unset(SCHEDULER_DATA, StringUtils.EMPTY));
-	}
-
-	public void removeScheduler(String user, String exploratory, String computational) {
-		updateOne(USER_INSTANCES, and(eq(USER, user), eq(EXPLORATORY_NAME, exploratory),
-				Filters.elemMatch(COMPUTATIONAL_RESOURCES, eq(COMPUTATIONAL_NAME, computational))),
-				unset(COMPUTATIONAL_RESOURCES + ".$." + SCHEDULER_DATA, StringUtils.EMPTY));
-	}
-
-	private FindIterable<Document> userInstancesWithScheduler(Bson statusCondition) {
-		return find(USER_INSTANCES,
-				and(
-						statusCondition,
-						schedulerNotNullCondition(), eq(CHECK_INACTIVITY_FLAG, false)
-				),
-				fields(excludeId(), include(USER, EXPLORATORY_NAME, PROJECT, SCHEDULER_DATA)));
-	}
-
-	private Stream<SchedulerJobData> computationalSchedulerDataStream(Document doc, DataEngineType computationalType,
-																	  UserInstanceStatus... computationalStatuses) {
-		return computationalSchedulerData(doc, computationalStatuses)
-				.filter(compResource -> fromDockerImageName(compResource.getString(IMAGE)) == computationalType)
-				.map(compResource -> toSchedulerData(doc, compResource));
-	}
-
-	private SchedulerJobData toSchedulerData(Document userInstanceDocument, Document compResource) {
-		final String user = userInstanceDocument.getString(USER);
-		final String project = userInstanceDocument.getString(PROJECT);
-		final String exploratoryName = userInstanceDocument.getString(EXPLORATORY_NAME);
-		final String computationalName = compResource.getString(COMPUTATIONAL_NAME);
-		final SchedulerJobDTO schedulerData = convertFromDocument((Document) compResource.get(SCHEDULER_DATA),
-				SchedulerJobDTO.class);
-		return new SchedulerJobData(user, exploratoryName, computationalName, project, schedulerData);
-	}
-
-	@SuppressWarnings("unchecked")
-	private Stream<Document> computationalSchedulerData(Document doc, UserInstanceStatus... computationalStatuses) {
-		final Set<String> statusSet = Arrays.stream(computationalStatuses)
-				.map(UserInstanceStatus::toString)
-				.collect(Collectors.toSet());
-		return ((List<Document>) doc.get(COMPUTATIONAL_RESOURCES))
-				.stream()
-				.filter(compResource -> Objects.nonNull(compResource.get(SCHEDULER_DATA)) &&
-						statusSet.contains(compResource.getString(STATUS)));
-	}
-}
-
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SecurityDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SecurityDAO.java
deleted file mode 100644
index a0ec24f..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SecurityDAO.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.exceptions.DlabException;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.mongodb.client.FindIterable;
-import com.mongodb.client.model.Projections;
-import org.bson.Document;
-import org.keycloak.representations.AccessTokenResponse;
-
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.backendapi.dao.MongoCollections.ROLES;
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.gte;
-import static com.mongodb.client.model.Filters.ne;
-import static com.mongodb.client.model.Projections.exclude;
-import static com.mongodb.client.model.Projections.fields;
-import static com.mongodb.client.model.Projections.include;
-
-/**
- * DAO write the attempt of user login into DLab.
- */
-@Singleton
-public class SecurityDAO extends BaseDAO {
-	private static final String SECURITY_COLLECTION = "security";
-	private static final String TOKEN_RESPONSE = "tokenResponse";
-	private static final String LAST_ACCESS = "last_access";
-
-	@Inject
-	private SelfServiceApplicationConfiguration conf;
-
-	/**
-	 * Return the roles or throw exception if roles collection does not exists.
-	 */
-	public FindIterable<Document> getRoles() {
-		if (!collectionExists(ROLES)) {
-			throw new DlabException("Collection \"" + ROLES + "\" does not exists.");
-		}
-		return find(ROLES, ne(ID, "_Example"), fields(exclude("description")));
-	}
-
-	public Map<String, Set<String>> getGroups() {
-		return stream(find("userGroups"))
-				.collect(Collectors.toMap(d -> d.getString(ID).toLowerCase(), this::toUsers));
-
-	}
-
-	public void saveUser(String userName, AccessTokenResponse accessTokenResponse) {
-		updateOne(SECURITY_COLLECTION, eq(ID, userName),
-				new Document(SET,
-						new Document()
-								.append(ID, userName)
-								.append("created", new Date())
-								.append(LAST_ACCESS, new Date())
-								.append(TOKEN_RESPONSE, convertToBson(accessTokenResponse))),
-				true);
-	}
-
-	public void updateUser(String userName, AccessTokenResponse accessTokenResponse) {
-		updateOne(SECURITY_COLLECTION, eq(ID, userName),
-				new Document(SET,
-						new Document()
-								.append(ID, userName)
-								.append(LAST_ACCESS, new Date())
-								.append(TOKEN_RESPONSE, convertToBson(accessTokenResponse))));
-	}
-
-	public Optional<UserInfo> getUser(String token) {
-		return Optional.ofNullable(mongoService.getCollection(SECURITY_COLLECTION)
-				.findOneAndUpdate(and(eq(TOKEN_RESPONSE + ".access_token", token), gte(LAST_ACCESS,
-						new Date(new Date().getTime() - conf.getInactiveUserTimeoutMillSec()))), new Document("$set",
-						new Document(LAST_ACCESS, new Date()))))
-				.map(d -> new UserInfo(d.getString(ID), token));
-	}
-
-
-	public Optional<AccessTokenResponse> getTokenResponse(String user) {
-		return findOne(SECURITY_COLLECTION, eq(ID, user), Projections.fields(include(TOKEN_RESPONSE)))
-				.map(d -> convertFromDocument((Document) d.get(TOKEN_RESPONSE), AccessTokenResponse.class));
-	}
-
-	@SuppressWarnings("unchecked")
-	private Set<String> toUsers(Document d) {
-		final Object users = d.get("users");
-		return users == null ? Collections.emptySet() :
-				new HashSet<>(((List<String>) users).stream().map(String::toLowerCase).collect(Collectors.toList()));
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SettingsDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SettingsDAO.java
deleted file mode 100644
index d5770e1..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SettingsDAO.java
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * 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.exceptions.DlabException;
-import com.mongodb.client.model.UpdateOptions;
-import org.apache.commons.lang3.StringUtils;
-import org.bson.Document;
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.backendapi.dao.MongoCollections.SETTINGS;
-import static com.epam.dlab.backendapi.dao.MongoSetting.*;
-import static com.mongodb.client.model.Filters.eq;
-import static org.apache.commons.lang3.StringUtils.EMPTY;
-
-/**
- * Stores the environment settings.
- */
-public class SettingsDAO extends BaseDAO {
-	private static final String VALUE = "value";
-
-	/**
-	 * Returns the base name of service.
-	 */
-	public String getServiceBaseName() {
-		return getSetting(SERIVICE_BASE_NAME);
-	}
-
-	public void setServiceBaseName(String sbn) {
-		setSetting(SERIVICE_BASE_NAME, sbn);
-	}
-
-	/**
-	 * Returns the name of OS family.
-	 */
-	public String getConfOsFamily() {
-		return getSetting(CONF_OS_FAMILY);
-	}
-
-	public void setConfOsFamily(String osFamily) {
-		setSetting(CONF_OS_FAMILY, osFamily);
-	}
-
-	/**
-	 * Returns the name of directory for user key.
-	 */
-	public String getConfKeyDir() {
-		return getSetting(CONF_KEY_DIRECTORY);
-	}
-
-	public void setConfKeyDir(String confKeyDir) {
-		setSetting(CONF_KEY_DIRECTORY, confKeyDir);
-	}
-
-	/**
-	 * Returns the name of tag for resource id.
-	 */
-	public String getConfTagResourceId() {
-		return getSetting(CONF_TAG_RESOURCE_ID);
-	}
-
-	public void setConfTagResourceId(String confTagResourceId) {
-		setSetting(CONF_TAG_RESOURCE_ID, confTagResourceId);
-	}
-
-	public Optional<Integer> getMaxBudget() {
-		return getOptionalSetting(CONF_MAX_BUDGET)
-				.map(Integer::valueOf);
-
-	}
-
-	public String getAwsZone() {
-		return getSetting(AWS_ZONE);
-	}
-
-	public void setAwsZone(String awsZone) {
-		setSetting(AWS_ZONE, awsZone);
-	}
-
-	public String getLdapHost() {
-		return getSetting(LDAP_HOSTNAME);
-	}
-
-	public void setLdapHost(String ldapHost) {
-		setSetting(LDAP_HOSTNAME, ldapHost);
-	}
-
-	public String getLdapOu() {
-		return getSetting(LDAP_OU);
-	}
-
-	public void setLdapOu(String ldapOu) {
-		setSetting(LDAP_OU, ldapOu);
-	}
-
-	public String getLdapDn() {
-		return getSetting(LDAP_DN);
-	}
-
-	public void setLdapDn(String ldapDn) {
-		setSetting(LDAP_DN, ldapDn);
-	}
-
-	public String getLdapUser() {
-		return getSetting(LDAP_USER);
-	}
-
-	public void setLdapUser(String user) {
-		setSetting(LDAP_USER, user);
-	}
-
-	public String getLdapPassword() {
-		return getSetting(LDAP_PASSWORD);
-	}
-
-	public void setLdapPassword(String ldapPassword) {
-		setSetting(LDAP_PASSWORD, ldapPassword);
-	}
-
-	/**
-	 * Returns the name of AWS region.
-	 */
-	public String getAwsRegion() {
-		return getSetting(AWS_REGION);
-	}
-
-	public void setAwsRegion(String awsRegion) {
-		setSetting(AWS_REGION, awsRegion);
-	}
-
-	/**
-	 * Returns the id of security group.
-	 */
-	public String getAwsSecurityGroups() {
-		return getSetting(AWS_SECURITY_GROUPS);
-	}
-
-	public void setAwsSecurityGroups(String awsSecurityGroups) {
-		setSetting(AWS_SECURITY_GROUPS, awsSecurityGroups);
-	}
-
-	/**
-	 * Returns the id of virtual private cloud for AWS account.
-	 */
-	public String getAwsVpcId() {
-		return getSetting(AWS_VPC_ID);
-	}
-
-	public void setAwsVpcId(String awsVpcId) {
-		setSetting(AWS_VPC_ID, awsVpcId);
-	}
-
-	/**
-	 * Returns the id of virtual private cloud subnet for AWS account.
-	 */
-	public void setAwsSubnetId(String awsSubnetId) {
-		setSetting(AWS_SUBNET_ID, awsSubnetId);
-	}
-
-	public String getAwsSubnetId() {
-		return getSetting(AWS_SUBNET_ID);
-	}
-
-	public String getAwsNotebookVpcId() {
-		return getSetting(AWS_NOTEBOOK_VPC_ID);
-	}
-
-	public void setSsnStorageAccountTagName(String ssnStorageAccountTagName) {
-		setSetting(SSN_STORAGE_ACCOUNT_TAG_NAME, ssnStorageAccountTagName);
-	}
-
-	public String getSsnStorageAccountTagName() {
-		return getSetting(SSN_STORAGE_ACCOUNT_TAG_NAME);
-	}
-
-	public void setSharedStorageAccountTagName(String sharedStorageAccountTagName) {
-		setSetting(SHARED_STORAGE_ACCOUNT_TAG_NAME, sharedStorageAccountTagName);
-	}
-
-	public String getSharedStorageAccountTagName() {
-		return getSetting(SHARED_STORAGE_ACCOUNT_TAG_NAME);
-	}
-
-	public void setPeeringId(String peeringId) {
-		setSetting(PEERING_ID, peeringId);
-	}
-
-	public void setAwsNotebookVpcId(String awsNotebookVpcId) {
-		setSetting(AWS_NOTEBOOK_VPC_ID, awsNotebookVpcId);
-	}
-
-	public String getAwsNotebookSubnetId() {
-		return getSetting(AWS_NOTEBOOK_SUBNET_ID);
-	}
-
-	public void setAwsNotebookSubnetId(String awsNotebookSubnetId) {
-		setSetting(AWS_NOTEBOOK_SUBNET_ID, awsNotebookSubnetId);
-	}
-
-	public String getAzureRegion() {
-		return getSetting(AZURE_REGION);
-	}
-
-	public String getAzureResourceGroupName() {
-		return getSetting(AZURE_RESOURCE_GROUP_NAME);
-	}
-
-	public String getAzureSubnetName() {
-		return getSetting(AZURE_SUBNET_NAME);
-	}
-
-	public String getAzureVpcName() {
-		return getSetting(AZURE_VPC_NAME);
-	}
-
-	public String getAzureSecurityGroupName() {
-		return getSetting(AZURE_SECURITY_GROUP_NAME);
-	}
-
-	public String getAzureEdgeInstanceSize() {
-		return getSetting(AZURE_EDGE_INSTANCE_SIZE);
-	}
-
-	public String getSsnInstanceSize() {
-		return getSetting(SSN_INSTANCE_SIZE);
-	}
-
-	public String getAzureDataLakeNameTag() {
-		return getSetting(AZURE_DATA_LAKE_NAME_TAG, "");
-	}
-
-	public boolean isAzureDataLakeEnabled() {
-		String dataLakeTagName = getAzureDataLakeNameTag();
-		return dataLakeTagName != null && !dataLakeTagName.isEmpty();
-	}
-
-	public String getAzureDataLakeClientId() {
-		return getSetting(AZURE_DATA_LAKE_CLIENT_ID);
-	}
-
-	public void setAzureRegion(String region) {
-		setSetting(AZURE_REGION, region);
-	}
-
-	public void setAzureResourceGroupName(String resourceGroupName) {
-		setSetting(AZURE_RESOURCE_GROUP_NAME, resourceGroupName);
-	}
-
-	public void setAzureSubnetName(String subnetName) {
-		setSetting(AZURE_SUBNET_NAME, subnetName);
-	}
-
-	public void setAzureVpcName(String vpcName) {
-		setSetting(AZURE_VPC_NAME, vpcName);
-	}
-
-	public void setAzureSecurityGroupName(String securityGroupName) {
-		setSetting(AZURE_SECURITY_GROUP_NAME, securityGroupName);
-	}
-
-	public void setAzureEdgeInstanceSize(String azureEdgeInstanceSize) {
-		setSetting(AZURE_EDGE_INSTANCE_SIZE, azureEdgeInstanceSize);
-	}
-
-	public void setSsnInstanceSize(String ssnInstanceSize) {
-		setSetting(SSN_INSTANCE_SIZE, ssnInstanceSize);
-	}
-
-	public void setAzureDataLakeNameTag(String dataLakeNameTag) {
-		setSetting(AZURE_DATA_LAKE_NAME_TAG, dataLakeNameTag);
-	}
-
-	public void setAzureDataLakeClientId(String dataLakeClientId) {
-		setSetting(AZURE_DATA_LAKE_CLIENT_ID, dataLakeClientId);
-	}
-
-	public String getGcpRegion() {
-		return getSetting(GCP_REGION);
-	}
-
-	public void setGcpRegion(String region) {
-		setSetting(GCP_REGION, region);
-	}
-
-	public String getGcpZone() {
-		return getSetting(GCP_ZONE);
-	}
-
-	public void setGcpZone(String zone) {
-		setSetting(GCP_ZONE, zone);
-	}
-
-	public String getGcpSubnetName() {
-		return getSetting(GCP_SUBNET_NAME);
-	}
-
-	public void setGcpSubnetName(String subnet) {
-		setSetting(GCP_SUBNET_NAME, subnet);
-	}
-
-	public String getGcpProjectId() {
-		return getSetting(GCP_PROJECT_ID);
-	}
-
-	public void setGcpProjectId(String projectId) {
-		setSetting(GCP_PROJECT_ID, projectId);
-	}
-
-	public String getGcpVpcName() {
-		return getSetting(GCP_VPC_NAME);
-	}
-
-	public void setGcpVpcName(String vpcName) {
-		setSetting(GCP_VPC_NAME, vpcName);
-	}
-
-	public void setMaxBudget(Long budget) {
-		setSetting(CONF_MAX_BUDGET, budget.toString());
-	}
-
-	public void removeSetting(MongoSetting setting) {
-		getCollection(SETTINGS).deleteOne(eq(ID, setting.getId()));
-	}
-
-	public Map<String, Object> getSettings() {
-		return stream(getCollection(SETTINGS).find())
-				.collect(Collectors.toMap(d -> d.getString(ID), d -> d.get(VALUE)));
-	}
-
-	/**
-	 * Returns the value of property from Mongo database.
-	 *
-	 * @param setting the name of property.
-	 */
-	private String getSetting(MongoSetting setting) {
-		Document d = settingDocument(setting);
-		if (d == null) {
-			throw new DlabException("Setting property " + setting + " not found");
-		}
-		return d.getOrDefault(VALUE, EMPTY).toString();
-	}
-
-	private Optional<String> getOptionalSetting(MongoSetting setting) {
-		Document d = settingDocument(setting);
-		return Optional.ofNullable(d).map(doc -> doc.getString(VALUE));
-	}
-
-	private Document settingDocument(MongoSetting setting) {
-		return mongoService
-				.getCollection(SETTINGS)
-				.find(eq(ID, setting.getId()))
-				.first();
-	}
-
-	private void setSetting(MongoSetting mongoSetting, String value) {
-		if (StringUtils.isNotEmpty(value)) {
-			mongoService.getCollection(SETTINGS)
-					.updateOne(eq(ID, mongoSetting.getId()), new Document("$set", new Document(VALUE, value)),
-							new UpdateOptions().upsert(true));
-		}
-	}
-
-
-	private String getSetting(MongoSetting setting, String defaultValue) {
-		Document d = settingDocument(setting);
-		if (d == null) {
-			return defaultValue;
-		}
-		return d.getOrDefault(VALUE, defaultValue).toString();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDAO.java
deleted file mode 100644
index 9d6b72b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDAO.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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 java.util.Set;
-
-public interface UserGroupDAO {
-	void addUsers(String group, Set<String> users);
-
-	void updateUsers(String group, Set<String> users);
-
-	void removeGroup(String groupId);
-
-	Set<String> getUserGroups(String user);
-
-	Set<String> getUsers(String group);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDAOImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDAOImpl.java
deleted file mode 100644
index 39fc11a..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDAOImpl.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.exceptions.DlabException;
-import com.google.inject.Singleton;
-import org.bson.Document;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.backendapi.dao.MongoCollections.USER_GROUPS;
-import static com.mongodb.client.model.Filters.elemMatch;
-import static com.mongodb.client.model.Filters.eq;
-
-@Singleton
-public class UserGroupDAOImpl extends BaseDAO implements UserGroupDAO {
-
-	private static final String USERS_FIELD = "users";
-
-	@Override
-	public void addUsers(String group, Set<String> users) {
-		updateOne(USER_GROUPS, eq(ID, group), addToSet(USERS_FIELD, users), true);
-	}
-
-	@Override
-	public void updateUsers(String group, Set<String> users) {
-		updateOne(USER_GROUPS, eq(ID, group), new Document(SET, new Document(USERS_FIELD, users)), true);
-	}
-
-	@Override
-	public void removeGroup(String groupId) {
-        deleteOne(USER_GROUPS, eq(ID, groupId));
-    }
-
-    @Override
-    public Set<String> getUserGroups(String user) {
-        return stream(find(USER_GROUPS, elemMatch(USERS_FIELD, new Document("$regex", "^" + user + "$")
-                .append("$options", "i"))))
-                .map(document -> document.getString(ID))
-                .collect(Collectors.toSet());
-    }
-
-    @Override
-    public Set<String> getUsers(String group) {
-        return new HashSet<>(findOne(USER_GROUPS, eq(ID, group))
-                .map(document -> (List<String>) document.get(USERS_FIELD))
-                .orElseThrow(() -> new DlabException(String.format("Group %s not found", group))));
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserRoleDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserRoleDAO.java
deleted file mode 100644
index 5de090c..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserRoleDAO.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.resources.dto.UserGroupDto;
-import com.epam.dlab.backendapi.resources.dto.UserRoleDto;
-import com.epam.dlab.cloud.CloudProvider;
-
-import java.util.List;
-import java.util.Set;
-
-public interface UserRoleDAO {
-	List<UserRoleDto> findAll();
-
-	void insert(UserRoleDto dto);
-
-	void insert(List<UserRoleDto> roles);
-
-	boolean update(UserRoleDto dto);
-
-	void updateMissingRoles(CloudProvider cloudProvider);
-
-	boolean addGroupToRole(Set<String> groups, Set<String> roleIds);
-
-	void removeGroupWhenRoleNotIn(String group, Set<String> roleIds);
-
-	void removeUnnecessaryRoles(CloudProvider cloudProviderToBeRemoved, List<CloudProvider> remainingProviders);
-
-	void remove(String roleId);
-
-	boolean removeGroup(String groupId);
-
-	List<UserGroupDto> aggregateRolesByGroup();
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserRoleDAOImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserRoleDAOImpl.java
deleted file mode 100644
index 2eced33..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserRoleDAOImpl.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * 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.resources.dto.UserGroupDto;
-import com.epam.dlab.backendapi.resources.dto.UserRoleDto;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.exceptions.DlabException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.inject.Singleton;
-import com.mongodb.client.model.BsonField;
-import com.mongodb.client.result.UpdateResult;
-import lombok.extern.slf4j.Slf4j;
-import org.bson.Document;
-import org.bson.conversions.Bson;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static com.epam.dlab.backendapi.dao.MongoCollections.USER_GROUPS;
-import static com.mongodb.client.model.Aggregates.group;
-import static com.mongodb.client.model.Aggregates.lookup;
-import static com.mongodb.client.model.Aggregates.project;
-import static com.mongodb.client.model.Aggregates.unwind;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.in;
-import static com.mongodb.client.model.Filters.not;
-import static java.lang.String.format;
-import static java.util.stream.Collectors.toList;
-
-@Singleton
-@Slf4j
-public class UserRoleDAOImpl extends BaseDAO implements UserRoleDAO {
-	private static final ObjectMapper MAPPER = new ObjectMapper();
-	private static final String[] DEFAULT_AWS_SHAPES = {"nbShapes_t2.medium_fetching", "compShapes_c4.xlarge_fetching"};
-	private static final String[] DEFAULT_GCP_SHAPES = {"compShapes_n1-standard-2_fetching", "nbShapes_n1-standard-2_fetching"};
-	private static final String[] DEFAULT_AZURE_SHAPES = {"nbShapes_Standard_E4s_v3_fetching", "compShapes_Standard_E4s_v3_fetching"};
-	private static final String ROLES_FILE_FORMAT = "/mongo/%s/mongo_roles.json";
-	private static final String USERS_FIELD = "users";
-	private static final String GROUPS_FIELD = "groups";
-	private static final String DESCRIPTION = "description";
-	private static final String TYPE = "type";
-	private static final String CLOUD = "cloud";
-	private static final String ROLES = "roles";
-	private static final String GROUPS = "$groups";
-	private static final String GROUP = "group";
-	private static final String EXPLORATORY_SHAPES_FIELD = "exploratory_shapes";
-	private static final String PAGES_FIELD = "pages";
-	private static final String EXPLORATORIES_FIELD = "exploratories";
-	private static final String COMPUTATIONALS_FIELD = "computationals";
-	private static final String GROUP_INFO = "groupInfo";
-
-
-	@Override
-	public List<UserRoleDto> findAll() {
-		return find(MongoCollections.ROLES, UserRoleDto.class);
-	}
-
-	@Override
-	public void insert(UserRoleDto dto) {
-		insertOne(MongoCollections.ROLES, dto, dto.getId());
-	}
-
-	@Override
-	public void insert(List<UserRoleDto> roles) {
-		roles.forEach(this::insert);
-	}
-
-	@Override
-	public boolean update(UserRoleDto dto) {
-		final Document userRoleDocument = convertToBson(dto).append(TIMESTAMP, new Date());
-		return conditionMatched(updateOne(MongoCollections.ROLES,
-				eq(ID, dto.getId()),
-				new Document(SET, userRoleDocument)));
-	}
-
-	@Override
-	public void updateMissingRoles(CloudProvider cloudProvider) {
-		getUserRoleFromFile(cloudProvider)
-				.stream()
-				.peek(u -> u.setGroups(Collections.emptySet()))
-				.filter(u -> findAll()
-						.stream()
-						.map(UserRoleDto::getId)
-						.noneMatch(id -> id.equals(u.getId())))
-				.forEach(this::insert);
-
-		addGroupToRole(aggregateRolesByGroup()
-						.stream()
-						.map(UserGroupDto::getGroup)
-						.collect(Collectors.toSet()),
-				getDefaultShapes(cloudProvider));
-	}
-
-	@Override
-	public boolean addGroupToRole(Set<String> groups, Set<String> roleIds) {
-		return conditionMatched(updateMany(MongoCollections.ROLES, in(ID, roleIds), addToSet(GROUPS_FIELD,
-				groups)));
-	}
-
-	@Override
-	public void removeGroupWhenRoleNotIn(String group, Set<String> roleIds) {
-		updateMany(MongoCollections.ROLES, not(in(ID, roleIds)), pull(GROUPS_FIELD, group));
-	}
-
-	@Override
-	public void removeUnnecessaryRoles(CloudProvider cloudProviderToBeRemoved, List<CloudProvider> remainingProviders) {
-		if (remainingProviders.contains(cloudProviderToBeRemoved)) {
-			return;
-		}
-		List<UserRoleDto> remainingRoles = new ArrayList<>();
-		remainingProviders.forEach(p -> remainingRoles.addAll(getUserRoleFromFile(p)));
-
-		getUserRoleFromFile(cloudProviderToBeRemoved)
-				.stream()
-				.filter(role -> UserRoleDto.cloudSpecificTypes().contains(role.getType()))
-				.map(UserRoleDto::getId)
-				.filter(u -> remainingRoles
-						.stream()
-						.map(UserRoleDto::getId)
-						.noneMatch(id -> id.equals(u)))
-				.forEach(this::remove);
-	}
-
-	@Override
-	public void remove(String roleId) {
-		deleteOne(MongoCollections.ROLES, eq(ID, roleId));
-	}
-
-	@Override
-	public boolean removeGroup(String groupId) {
-		return conditionMatched(updateMany(MongoCollections.ROLES, in(GROUPS_FIELD, groupId), pull(GROUPS_FIELD,
-				groupId)));
-	}
-
-	@Override
-	public List<UserGroupDto> aggregateRolesByGroup() {
-		final Document role = roleDocument();
-		final Bson groupBy = group(GROUPS, new BsonField(ROLES, new Document(ADD_TO_SET, role)));
-		final Bson lookup = lookup(USER_GROUPS, ID, ID, GROUP_INFO);
-		final List<Bson> pipeline = Arrays.asList(unwind(GROUPS), groupBy, lookup,
-				project(new Document(GROUP, "$" + ID).append(GROUP_INFO, elementAt(GROUP_INFO, 0))
-						.append(ROLES, "$" + ROLES)),
-				project(new Document(GROUP, "$" + ID).append(USERS_FIELD, "$" + GROUP_INFO + "." + USERS_FIELD)
-						.append(ROLES, "$" + ROLES)));
-
-		return stream(aggregate(MongoCollections.ROLES, pipeline))
-				.map(d -> convertFromDocument(d, UserGroupDto.class))
-				.collect(toList());
-	}
-
-	private List<UserRoleDto> getUserRoleFromFile(CloudProvider cloudProvider) {
-		try (InputStream is = getClass().getResourceAsStream(format(ROLES_FILE_FORMAT, cloudProvider.getName()))) {
-			return MAPPER.readValue(is, new TypeReference<List<UserRoleDto>>() {
-			});
-		} catch (IOException e) {
-			log.error("Can not marshall dlab roles due to: {}", e.getMessage(), e);
-			throw new IllegalStateException("Can not marshall dlab roles due to: " + e.getMessage());
-		}
-	}
-
-	private Set<String> getDefaultShapes(CloudProvider cloudProvider) {
-		if (cloudProvider == CloudProvider.AWS) {
-			return Stream.of(DEFAULT_AWS_SHAPES).collect(Collectors.toSet());
-		} else if (cloudProvider == CloudProvider.GCP) {
-			return Stream.of(DEFAULT_GCP_SHAPES).collect(Collectors.toSet());
-		} else if (cloudProvider == CloudProvider.AZURE) {
-			return Stream.of(DEFAULT_AZURE_SHAPES).collect(Collectors.toSet());
-		} else {
-			throw new DlabException("Unsupported cloud provider " + cloudProvider);
-		}
-	}
-
-	private Document roleDocument() {
-		return new Document().append(ID, "$" + ID)
-				.append(DESCRIPTION, "$" + DESCRIPTION)
-				.append(TYPE, "$" + TYPE)
-				.append(CLOUD, "$" + CLOUD)
-				.append(USERS_FIELD, "$" + USERS_FIELD)
-				.append(EXPLORATORY_SHAPES_FIELD, "$" + EXPLORATORY_SHAPES_FIELD)
-				.append(PAGES_FIELD, "$" + PAGES_FIELD)
-				.append(EXPLORATORIES_FIELD, "$" + EXPLORATORIES_FIELD)
-				.append(COMPUTATIONALS_FIELD, "$" + COMPUTATIONALS_FIELD);
-	}
-
-	private boolean conditionMatched(UpdateResult updateResult) {
-		return updateResult.getMatchedCount() > 0;
-	}
-
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserSettingsDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserSettingsDAO.java
deleted file mode 100644
index 695ae0c..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserSettingsDAO.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.UserDTO;
-import io.dropwizard.auth.Auth;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.Optional;
-
-import static com.epam.dlab.backendapi.dao.MongoCollections.USER_SETTINGS;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Updates.set;
-
-/**
- * DAO for the user preferences.
- */
-public class UserSettingsDAO extends BaseDAO {
-	private static final String USER_UI_SETTINGS_FIELD = "userUISettings";
-	private static final String USER_ALLOWED_BUDGET = "allowedBudget";
-
-	/**
-	 * Returns the user preferences of UI dashboard.
-	 *
-	 * @param userInfo user info.
-	 * @return JSON content.
-	 */
-	public String getUISettings(@Auth UserInfo userInfo) {
-		return findOne(USER_SETTINGS, eq(ID, userInfo.getName()))
-				.map(d -> d.getString(USER_UI_SETTINGS_FIELD))
-				.orElse(StringUtils.EMPTY);
-	}
-
-	/**
-	 * Store the user preferences of UI dashboard.
-	 *
-	 * @param userInfo user info.
-	 * @param settings user preferences in JSON format.
-	 */
-	public void setUISettings(UserInfo userInfo, String settings) {
-		updateOne(USER_SETTINGS,
-				eq(ID, userInfo.getName()),
-				set(USER_UI_SETTINGS_FIELD, settings),
-				true);
-	}
-
-	public void updateBudget(UserDTO allowedBudgetDTO) {
-		updateOne(USER_SETTINGS,
-				eq(ID, allowedBudgetDTO.getName()),
-				set(USER_ALLOWED_BUDGET, allowedBudgetDTO.getBudget()),
-				true);
-	}
-
-	public Optional<Integer> getAllowedBudget(String user) {
-		return findOne(USER_SETTINGS, eq(ID, user))
-				.flatMap(d -> Optional.ofNullable(d.getInteger(USER_ALLOWED_BUDGET)));
-	}
-
-}
\ No newline at end of file
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
deleted file mode 100644
index c1f3c18..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditActionEnum.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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, SET_UP_SCHEDULER, START, STOP, TERMINATE, RECONFIGURE, UPDATE, CONNECT, DISCONNECT, UPLOAD, DOWNLOAD, DELETE, INSTALL_LIBS, FOLLOW_LINK, LOG_IN
-}
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
deleted file mode 100644
index 22d939d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditCreateDTO.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import org.hibernate.validator.constraints.NotBlank;
-
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class AuditCreateDTO {
-    @NotBlank(message = "field cannot be empty")
-    @JsonProperty("resource_name")
-    private final String resourceName;
-    @NotBlank(message = "field cannot be empty")
-    private final String info;
-    private final AuditResourceTypeEnum type;
-}
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
deleted file mode 100644
index 442522f..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.Builder;
-import lombok.Data;
-
-import java.util.Date;
-
-@Data
-@Builder
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class AuditDTO {
-    private final String user;
-    private final AuditActionEnum action;
-    private final AuditResourceTypeEnum type;
-    private final String project;
-    private final String resourceName;
-    private final String info;
-    private Date timestamp;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditPaginationDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditPaginationDTO.java
deleted file mode 100644
index 7acff35..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditPaginationDTO.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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 com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Data;
-
-import java.util.List;
-import java.util.Set;
-
-@Data
-@Builder
-public class AuditPaginationDTO {
-    @JsonProperty("page_count")
-    private final int totalPageCount;
-    private final List<AuditDTO> audit;
-    @JsonProperty("user_filter")
-    private final Set<String> userFilter;
-    @JsonProperty("project_filter")
-    private final Set<String> projectFilter;
-    @JsonProperty("resource_name_filter")
-    private final Set<String> resourceNameFilter;
-    @JsonProperty("resource_type_filter")
-    private final Set<String> resourceTypeFilter;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditResourceTypeEnum.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditResourceTypeEnum.java
deleted file mode 100644
index e5425d2..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditResourceTypeEnum.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 AuditResourceTypeEnum {
-    PROJECT, EDGE_NODE, NOTEBOOK, COMPUTE, BUCKET, ENDPOINT, GROUP, IMAGE, GIT_ACCOUNT, LOG_IN, WEB_TERMINAL
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AutoCompleteEnum.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AutoCompleteEnum.java
deleted file mode 100644
index 46a3402..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AutoCompleteEnum.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 AutoCompleteEnum {
-	NONE, UPDATING, ENABLED
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/BillingReport.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/BillingReport.java
deleted file mode 100644
index 5d1d076..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/BillingReport.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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 com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Data;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@Data
-@Builder
-public class BillingReport {
-    private String sbn;
-    private String name;
-    @JsonProperty("report_lines")
-    private List<BillingReportLine> reportLines;
-    @JsonProperty("from")
-    private LocalDate usageDateFrom;
-    @JsonProperty("to")
-    private LocalDate usageDateTo;
-    @JsonProperty("total_cost")
-    private double totalCost;
-    private String currency;
-    @JsonProperty("is_full")
-    private boolean isReportHeaderCompletable;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/BillingReportLine.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/BillingReportLine.java
deleted file mode 100644
index a9cdd12..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/BillingReportLine.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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 com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.billing.BillingResourceType;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Data;
-
-import java.time.LocalDate;
-
-@Data
-@Builder
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class BillingReportLine {
-    private String dlabId;
-    private String application;
-    @JsonProperty("resource_name")
-    private String resourceName;
-    private String project;
-    private String endpoint;
-    private String user;
-    @JsonProperty("from")
-    private LocalDate usageDateFrom;
-    @JsonProperty("to")
-    private LocalDate usageDateTo;
-    private String usageDate;
-    private String product;
-    private String usageType;
-    private Double cost;
-    private String currency;
-    @JsonProperty("resource_type")
-    private BillingResourceType resourceType;
-    private UserInstanceStatus status;
-    private String shape;
-    private String exploratoryName;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/BudgetDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/BudgetDTO.java
deleted file mode 100644
index 801cf9b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/BudgetDTO.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class BudgetDTO {
-    private Integer value;
-    private boolean monthlyBudget;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/CreateProjectDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/CreateProjectDTO.java
deleted file mode 100644
index b92d480..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/CreateProjectDTO.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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 com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Pattern;
-import java.util.Set;
-
-@Data
-public class CreateProjectDTO {
-	@NotNull
-	private final String name;
-	@NotNull
-	private final Set<String> groups;
-	@NotNull
-	final Set<String> endpoints;
-	@NotNull
-	@Pattern(regexp = "^ssh-.*\\n?", message = "format is incorrect. Please use the openSSH format")
-	private final String key;
-	@NotNull
-	private final String tag;
-	@JsonProperty("shared_image_enabled")
-	private boolean sharedImageEnabled;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EndpointDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EndpointDTO.java
deleted file mode 100644
index fcf2475..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EndpointDTO.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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 com.epam.dlab.cloud.CloudProvider;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import org.hibernate.validator.constraints.NotBlank;
-import org.hibernate.validator.constraints.URL;
-
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class EndpointDTO {
-
-	private static final String URL_REGEXP_VALIDATION = "^(http(s)?)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
-	@NotBlank(message = "field cannot be empty")
-	private final String name;
-	@URL(regexp = URL_REGEXP_VALIDATION, message = "field is in improper format!")
-	private final String url;
-	@NotBlank(message = "field cannot be empty")
-	private final String account;
-	@JsonProperty("endpoint_tag")
-	private final String tag;
-	private final EndpointStatus status;
-	private final CloudProvider cloudProvider;
-
-	public enum EndpointStatus {
-		ACTIVE,
-		INACTIVE
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EndpointResourcesDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EndpointResourcesDTO.java
deleted file mode 100644
index 85f4418..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EndpointResourcesDTO.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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 com.epam.dlab.dto.UserInstanceDTO;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-@AllArgsConstructor
-public class EndpointResourcesDTO {
-    private List<UserInstanceDTO> exploratories;
-    private List<ProjectDTO> projects;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ExploratoryLibCache.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ExploratoryLibCache.java
deleted file mode 100644
index a33756f..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ExploratoryLibCache.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * 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 com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.LibraryAutoCompleteDTO;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.LibListComputationalDTO;
-import com.epam.dlab.dto.LibListExploratoryDTO;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.ComputationalAPI;
-import com.epam.dlab.rest.contracts.ExploratoryAPI;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-import io.dropwizard.lifecycle.Managed;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Cache of libraries for exploratory.
- */
-@Singleton
-public class ExploratoryLibCache implements Managed, Runnable {
-	private static final Logger LOGGER = LoggerFactory.getLogger(ExploratoryLibCache.class);
-
-	@Inject
-	@Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
-	private RESTService provisioningService;
-	@Inject
-	private RequestBuilder requestBuilder;
-	@Inject
-	private RequestId requestId;
-	@Inject
-	private EndpointService endpointService;
-
-	/**
-	 * Instance of cache.
-	 */
-	private static ExploratoryLibCache libCache;
-
-	/**
-	 * Thread of the cache.
-	 */
-	private Thread thread;
-
-	/**
-	 * List of libraries.
-	 */
-	private Map<String, ExploratoryLibList> cache = new HashMap<>();
-
-	/**
-	 * Return the list of libraries.
-	 */
-	public static ExploratoryLibCache getCache() {
-		synchronized (libCache) {
-			if (libCache.thread == null) {
-				LOGGER.debug("Library cache thread not running and will be started ...");
-				libCache.thread = new Thread(libCache, libCache.getClass().getSimpleName());
-				libCache.thread.start();
-			}
-		}
-		return libCache;
-	}
-
-	@Override
-	public void start() {
-		if (libCache == null) {
-			libCache = this;
-		}
-	}
-
-	@Override
-	public void stop() {
-		if (libCache != null) {
-			synchronized (libCache) {
-				if (libCache.thread != null) {
-					LOGGER.debug("Library cache thread will be stopped ...");
-					libCache.thread.interrupt();
-					libCache.thread = null;
-					LOGGER.debug("Library cache thread has been stopped");
-				}
-				libCache.cache.clear();
-			}
-		}
-	}
-
-	/**
-	 * Return the list of libraries for docker image and group start with prefix from cache.
-	 *
-	 * @param userInfo  the user info.
-	 * @param group     the name of group.
-	 * @param startWith the prefix for library name.
-	 * @return LibraryAutoCompleteDTO dto
-	 */
-	public LibraryAutoCompleteDTO getLibList(UserInfo userInfo, UserInstanceDTO userInstance, String group, String startWith) {
-		ExploratoryLibList libs = getLibs(userInfo, userInstance, group);
-		return libs.getLibs(group, startWith);
-	}
-
-	/**
-	 * Return the list of libraries for docker image from cache.
-	 *
-	 * @param userInfo     the user info.
-	 * @param userInstance userInstance
-	 * @param cacheKey     the group of library
-	 */
-	private ExploratoryLibList getLibs(UserInfo userInfo, UserInstanceDTO userInstance, String cacheKey) {
-		ExploratoryLibList libs;
-		synchronized (cache) {
-			cache.computeIfAbsent(cacheKey, libraries -> new ExploratoryLibList(cacheKey, null));
-			libs = cache.get(cacheKey);
-			if (libs.isUpdateNeeded() && !libs.isUpdating()) {
-				libs.setUpdating();
-				libs.setExpiredTime();
-				requestLibList(userInfo, userInstance, cacheKey);
-			}
-		}
-
-		return libs;
-	}
-
-	/**
-	 * Update the list of libraries for docker image in cache.
-	 *
-	 * @param group   the name of image.
-	 * @param content the content of libraries list.
-	 */
-	public void updateLibList(String group, String content) {
-		synchronized (cache) {
-			cache.remove(group);
-			cache.put(group, new ExploratoryLibList(group, content));
-		}
-	}
-
-	/**
-	 * Set updating library list to false
-	 *
-	 * @param groupName group name
-	 */
-	public void updateLibListStatus(String groupName) {
-		synchronized (cache) {
-			ExploratoryLibList exploratoryLibList = cache.get(groupName);
-			exploratoryLibList.setNotUpdating();
-		}
-	}
-
-	/**
-	 * Send request to provisioning service for the list of libraries.
-	 *
-	 * @param userInfo     the user info.
-	 * @param userInstance the notebook info.
-	 * @param group        the library group
-	 */
-	private void requestLibList(UserInfo userInfo, UserInstanceDTO userInstance, String group) {
-		try {
-
-			LOGGER.info("Ask docker for the list of libraries for user {} and exploratory {} computational {}",
-					userInfo.getName(), userInstance.getExploratoryId(),
-					userInstance.getResources());
-
-			String uuid;
-			if (userInstance.getResources() != null && !userInstance.getResources().isEmpty()) {
-				UserComputationalResource userComputationalResource = userInstance.getResources().get(0);
-				EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
-				LibListComputationalDTO dto = requestBuilder.newLibComputationalList(userInfo, userInstance,
-						userComputationalResource, endpointDTO, group);
-
-				uuid = provisioningService.post(endpointDTO.getUrl() + ComputationalAPI.COMPUTATIONAL_LIB_LIST,
-						userInfo.getAccessToken(),
-						dto, String.class);
-			} else {
-				EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
-				LibListExploratoryDTO dto = requestBuilder.newLibExploratoryList(userInfo, userInstance, endpointDTO, group);
-				uuid = provisioningService.post(endpointDTO.getUrl() + ExploratoryAPI.EXPLORATORY_LIB_LIST,
-						userInfo.getAccessToken(), dto,
-						String.class);
-			}
-
-			requestId.put(userInfo.getName(), uuid);
-
-		} catch (Exception e) {
-			LOGGER.warn("Ask docker for the status of resources for user {} and exploratory {} fails: {}",
-					userInfo.getName(), userInstance, e.getLocalizedMessage(), e);
-		}
-	}
-
-
-	@Override
-	public void run() {
-		while (true) {
-			try {
-				Thread.sleep(ExploratoryLibList.UPDATE_REQUEST_TIMEOUT_MILLIS);
-
-				synchronized (cache) {
-					cache.entrySet().removeIf(e -> e.getValue().isExpired());
-				}
-
-				if (cache.size() == 0) {
-					synchronized (libCache) {
-						thread = null;
-						LOGGER.debug("Library cache thread have no data and will be finished");
-						return;
-					}
-				}
-			} catch (InterruptedException e) {
-				LOGGER.trace("Library cache thread has been interrupted");
-				Thread.currentThread().interrupt();
-				break;
-			} catch (Exception e) {
-				LOGGER.warn("Library cache thread unhandled error: {}", e.getLocalizedMessage(), e);
-			}
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ExploratoryLibList.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ExploratoryLibList.java
deleted file mode 100644
index f264c78..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ExploratoryLibList.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * 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 com.epam.dlab.backendapi.resources.dto.LibraryAutoCompleteDTO;
-import com.epam.dlab.backendapi.resources.dto.LibraryDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.base.MoreObjects;
-import io.dropwizard.util.Duration;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.stream.Collectors;
-
-/**
- * Class to store the info about libraries.
- */
-@Slf4j
-public class ExploratoryLibList {
-
-	/**
-	 * Timeout in milliseconds when the info is out of date.
-	 */
-	private static final long EXPIRED_TIMEOUT_MILLIS = Duration.hours(2).toMilliseconds();
-
-	/**
-	 * Timeout in milliseconds until the is out of date.
-	 */
-	private static final long UPDATE_TIMEOUT_MILLIS = Duration.minutes(30).toMilliseconds();
-
-	/**
-	 * Timeout in milliseconds for request to update lib.
-	 */
-	protected static final long UPDATE_REQUEST_TIMEOUT_MILLIS = Duration.minutes(15).toMilliseconds();
-
-	/**
-	 * Group name.
-	 */
-	private String group;
-
-	/**
-	 * List of libraries group:libraries:version.
-	 */
-	private Map<String, Map<String, String>> libs = new HashMap<>();
-
-	/**
-	 * Time in milliseconds when the info is out of date.
-	 */
-	private long expiredTimeMillis = 0;
-
-	/**
-	 * Last access time in milliseconds to the info.
-	 */
-	private long accessTimeMillis = 0;
-
-	/**
-	 * Update start time in milliseconds.
-	 */
-	private long updateStartTimeMillis = 0;
-
-	/**
-	 * Update in progress.
-	 */
-	private boolean updating = false;
-
-
-	/**
-	 * Instantiate the list of libraries.
-	 *
-	 * @param group   the name of docker's image.
-	 * @param content JSON string.
-	 */
-	ExploratoryLibList(String group, String content) {
-		this.group = group;
-		if (content != null) {
-			setLibs(content);
-		}
-	}
-
-	/**
-	 * Return the list of all groups.
-	 */
-	public List<String> getGroupList() {
-		List<String> list = new ArrayList<>(libs.keySet());
-		Collections.sort(list);
-		return list;
-	}
-
-	/**
-	 * Return the name of docker image;
-	 */
-	public String getGroup() {
-		return group;
-	}
-
-	/**
-	 * Return the full list of libraries for group.
-	 *
-	 * @param group the name of group.
-	 */
-	public Map<String, String> getLibs(String group) {
-		return libs.get(group);
-	}
-
-	/**
-	 * Return the full list of libraries for group.
-	 *
-	 * @param content JSON string.
-	 */
-	private void setLibs(String content) {
-		ObjectMapper mapper = new ObjectMapper();
-		try {
-			synchronized (this) {
-				@SuppressWarnings("unchecked")
-				Map<String, Map<String, String>> map = mapper.readValue(content, Map.class);
-				for (Map.Entry<String, Map<String, String>> entry : map.entrySet()) {
-					Map<String, String> group = entry.getValue();
-					String groupName = entry.getKey();
-					libs.remove(groupName);
-					log.info("Update {} group with lib group {} with {} libraries", this.group, groupName, (group != null) ? group.size() : null);
-					libs.put(groupName, new TreeMap<>(group));
-				}
-				setExpiredTime();
-				updating = false;
-			}
-		} catch (IOException e) {
-			throw new DlabException("Cannot deserialize the list of libraries. " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	public void setExpiredTime() {
-		expiredTimeMillis = System.currentTimeMillis() + EXPIRED_TIMEOUT_MILLIS;
-		accessTimeMillis = System.currentTimeMillis();
-	}
-
-	/**
-	 * Search and return the list of libraries for name's prefix <b>startWith</b>.
-	 *
-	 * @param group     the name of group.
-	 * @param startWith the prefix for library name.
-	 * @return LibraryAutoCompleteDTO dto
-	 */
-	public LibraryAutoCompleteDTO getLibs(String group, String startWith) {
-		final String startsWithLower = startWith.toLowerCase();
-		Map<String, String> libMap = getLibs(group);
-		if (libMap == null) {
-			return LibraryAutoCompleteDTO.builder()
-					.autoComplete(isUpdating() ? AutoCompleteEnum.UPDATING : AutoCompleteEnum.NONE)
-					.libraries(Collections.emptyList())
-					.build();
-		}
-		List<LibraryDTO> libraries = libMap.entrySet()
-				.stream()
-				.filter(e -> e.getKey().toLowerCase().startsWith(startsWithLower))
-				.map(e -> new LibraryDTO(e.getKey(), e.getValue()))
-				.collect(Collectors.toList());
-
-		return LibraryAutoCompleteDTO.builder()
-				.autoComplete(AutoCompleteEnum.ENABLED)
-				.libraries(libraries)
-				.build();
-	}
-
-	/**
-	 * Set last access time.
-	 */
-	private void touch() {
-		accessTimeMillis = System.currentTimeMillis();
-	}
-
-	/**
-	 * Return <b>true</b> if the info is out of date.
-	 */
-	public boolean isExpired() {
-		touch();
-		return (expiredTimeMillis < System.currentTimeMillis());
-	}
-
-	/**
-	 * Return <b>true</b> if the info needs to update.
-	 */
-	public boolean isUpdateNeeded() {
-		touch();
-		return (accessTimeMillis > expiredTimeMillis - UPDATE_TIMEOUT_MILLIS);
-	}
-
-	/**
-	 * Set updating in progress.
-	 */
-	public void setUpdating() {
-		updateStartTimeMillis = System.currentTimeMillis();
-		updating = true;
-	}
-
-	/**
-	 * Set updating to false.
-	 */
-	public void setNotUpdating() {
-		updating = Boolean.FALSE;
-	}
-
-	/**
-	 * Return <b>true</b> if the update in progress.
-	 */
-	public boolean isUpdating() {
-		if (updating &&
-				updateStartTimeMillis + UPDATE_REQUEST_TIMEOUT_MILLIS < System.currentTimeMillis()) {
-			updating = false;
-		}
-		return updating;
-	}
-
-
-	@Override
-	public String toString() {
-		return MoreObjects.toStringHelper(this)
-				.add("group", group)
-				.add("expiredTimeMillis", expiredTimeMillis)
-				.add("accessTimeMillis", accessTimeMillis)
-				.add("updateStartTimeMillis", updateStartTimeMillis)
-				.add("isUpdating", updating)
-				.add("libs", (libs == null ? "null" : "..."))
-				.toString();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/MavenSearchArtifactResponse.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/MavenSearchArtifactResponse.java
deleted file mode 100644
index 3bf0154..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/MavenSearchArtifactResponse.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Getter;
-
-import java.util.List;
-
-@JsonIgnoreProperties(ignoreUnknown = true)
-@Getter
-public class MavenSearchArtifactResponse {
-
-	@JsonProperty("response")
-	private Response response;
-
-	public void setResponse(Response response) {
-		this.response = response;
-	}
-
-	public int getArtifactCount() {
-		return response.artifactCount;
-	}
-
-	public List<Response.Artifact> getArtifacts() {
-		return response.artifacts;
-	}
-
-	@JsonIgnoreProperties(ignoreUnknown = true)
-	public static class Response {
-		@JsonProperty("numFound")
-		private int artifactCount;
-		@JsonProperty("docs")
-		private List<Artifact> artifacts;
-
-		public void setArtifacts(List<Artifact> artifacts) {
-			this.artifacts = artifacts;
-		}
-
-		@JsonIgnoreProperties(ignoreUnknown = true)
-		public static class Artifact {
-			private String id;
-			@JsonProperty("v")
-			private String version;
-
-			public String getId() {
-				return id;
-			}
-
-			public void setId(String id) {
-				this.id = id;
-			}
-
-			public String getVersion() {
-				return version;
-			}
-
-			public void setVersion(String version) {
-				this.version = version;
-			}
-		}
-	}
-
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/NotebookTemplate.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/NotebookTemplate.java
deleted file mode 100644
index 12741c6..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/NotebookTemplate.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 NotebookTemplate {
-	JUPYTER("Jupyter notebook 6.0.2"),
-	JUPYTER_LAB("JupyterLab 0.35.6"),
-	ZEPPELIN("Apache Zeppelin 0.8.2"),
-	DEEP_LEARNING("Deep Learning  2.4"),
-	TENSOR("Jupyter with TensorFlow 2.1.0"),
-	TENSOR_RSTUDIO("RStudio with TensorFlow 2.1.0"),
-	RSTUDIO("RStudio 1.2.5033");
-
-	private String name;
-
-	NotebookTemplate(String name) {
-		this.name = name;
-	}
-
-	public String getName() {
-		return name;
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectDTO.java
deleted file mode 100644
index a8b30f2..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectDTO.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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 com.epam.dlab.dto.UserInstanceStatus;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Pattern;
-import java.util.List;
-import java.util.Set;
-
-@Data
-@Builder
-@AllArgsConstructor
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class ProjectDTO {
-	@NotNull
-	private final String name;
-	@NotNull
-	private final Set<String> groups;
-	@NotNull
-	@Pattern(regexp = "^ssh-.*\\n", message = "format is incorrect. Please use the openSSH format")
-	private final String key;
-	@NotNull
-	private final String tag;
-	private final BudgetDTO budget;
-	private final List<ProjectEndpointDTO> endpoints;
-	private final boolean sharedImageEnabled;
-
-
-	public enum Status {
-		CREATING,
-		ACTIVE,
-		FAILED,
-		DELETED,
-		DELETING,
-		DEACTIVATING,
-		ACTIVATING,
-		NOT_ACTIVE;
-
-		public static Status from(UserInstanceStatus userInstanceStatus) {
-			if (userInstanceStatus == UserInstanceStatus.RUNNING) {
-				return ACTIVE;
-			} else if (userInstanceStatus == UserInstanceStatus.TERMINATED) {
-				return DELETED;
-			} else if (userInstanceStatus == UserInstanceStatus.TERMINATING) {
-				return DELETING;
-			} else if (userInstanceStatus == UserInstanceStatus.STOPPING) {
-				return DEACTIVATING;
-			} else if (userInstanceStatus == UserInstanceStatus.STOPPED) {
-				return NOT_ACTIVE;
-			} else if (userInstanceStatus == UserInstanceStatus.STARTING) {
-				return ACTIVATING;
-			} else if (userInstanceStatus == UserInstanceStatus.CREATING) {
-				return CREATING;
-			} else if (userInstanceStatus == UserInstanceStatus.FAILED) {
-				return FAILED;
-			}
-			return Status.valueOf(userInstanceStatus.name());
-		}
-
-		public static UserInstanceStatus from(Status status) {
-			if (status == ACTIVE) {
-				return UserInstanceStatus.RUNNING;
-			} else if (status == ACTIVATING) {
-				return UserInstanceStatus.STARTING;
-			} else if (status == DEACTIVATING) {
-				return UserInstanceStatus.STOPPING;
-			} else if (status == NOT_ACTIVE) {
-				return UserInstanceStatus.STOPPED;
-			} else if (status == DELETING) {
-				return UserInstanceStatus.TERMINATING;
-			} else if (status == DELETED) {
-				return UserInstanceStatus.TERMINATED;
-			} else if (status == CREATING) {
-				return UserInstanceStatus.CREATING;
-			} else if (status == FAILED) {
-				return UserInstanceStatus.FAILED;
-			}
-			throw new IllegalArgumentException();
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectEndpointDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectEndpointDTO.java
deleted file mode 100644
index 66b1dac..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectEndpointDTO.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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 com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-import lombok.Data;
-
-@Data
-public class ProjectEndpointDTO {
-	private final String name;
-	private final UserInstanceStatus status;
-	private final EdgeInfo edgeInfo;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/RequestId.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/RequestId.java
deleted file mode 100644
index 7aa6bb0..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/RequestId.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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 com.epam.dlab.backendapi.dao.RequestIdDAO;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import io.dropwizard.util.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Date;
-import java.util.UUID;
-
-/** Stores and checks the id of requests for Provisioning Service.
- */
-@Singleton
-public class RequestId {
-    private static final Logger LOGGER = LoggerFactory.getLogger(RequestId.class);
-
-	/**	Timeout in milliseconds when the request id is out of date. */
-	private static final long EXPIRED_TIMEOUT_MILLIS = Duration.hours(12).toMilliseconds();
-
-	@Inject
-	private RequestIdDAO dao;
-	
-	/** Add the request id for user.
-	 * @param username the name of user.
-	 * @param uuid UUID.
-	 */
-	public String put(String username, String uuid) {
-		LOGGER.trace("Register request id {} for user {}", uuid, username);
-		dao.put(new RequestIdDTO()
-				.withId(uuid)
-				.withUser(username)
-				.withRequestTime(new Date())
-				.withExpirationTime(new Date(System.currentTimeMillis() + EXPIRED_TIMEOUT_MILLIS)));
-		return uuid;
-	}
-	
-	/** Generate, add and return new UUID.
-	 * @param username the name of user.
-	 * @return new UUID
-	 */
-	public String get(String username) {
-		return put(UUID.randomUUID().toString(), username);
-	}
-	
-	/** Remove UUID if it exist. 
-	 * @param uuid UUID.
-	 */
-	public void remove(String uuid) {
-		LOGGER.trace("Unregister request id {}", uuid);
-		dao.delete(uuid);
-	}
-
-	/** Check and remove UUID, if it not exists throw exception.
-	 * @param uuid UUID.
-	 * @return username
-	 */
-	public String checkAndRemove(String uuid) {
-		String username = dao.get(uuid).getUser();
-		LOGGER.trace("Unregister request id {} for user {}", uuid, username);
-		dao.delete(uuid);
-		return username;
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/RequestIdDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/RequestIdDTO.java
deleted file mode 100644
index c4074e3..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/RequestIdDTO.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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 java.util.Date;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-/** Store request id info.
- * @author Usein_Faradzhev
- *
- */
-public class RequestIdDTO {
-    @JsonProperty("_id")
-    private String id;
-    
-    @JsonProperty
-    private String user;
-
-    @JsonProperty
-    private Date requestTime;
-    
-    @JsonProperty
-    private Date expirationTime;
-    
-    /** Return request id. */
-    public String getId() {
-        return id;
-    }
-
-    /** Set request id. */
-    public void setId(String id) {
-        this.id = id;
-    }
-
-    /** Set request id. */
-    public RequestIdDTO withId(String id) {
-        setId(id);
-        return this;
-    }
-
-    /** Return user name. */
-    public String getUser() {
-        return user;
-    }
-
-    /** Set user name. */
-    public void setUser(String user) {
-        this.user = user;
-    }
-
-    /** Set user name. */
-    public RequestIdDTO withUser(String user) {
-        setUser(user);
-        return this;
-    }
-
-    /** Return request time. */
-    public Date getRequestTime() {
-        return requestTime;
-    }
-
-    /** Set request time. */
-    public void setRequestTime(Date requestTime) {
-        this.requestTime = requestTime;
-    }
-
-    /** Set request time. */
-    public RequestIdDTO withRequestTime(Date requestTime) {
-        setRequestTime(requestTime);
-        return this;
-    }
-
-    /** Return expiration time. */
-    public Date getExpirationTime() {
-        return expirationTime;
-    }
-
-    /** Set expiration time. */
-    public void setExpirationTime(Date expirationTime) {
-        this.expirationTime = expirationTime;
-    }
-
-    /** Set expiration time. */
-    public RequestIdDTO withExpirationTime(Date expirationTime) {
-        setExpirationTime(expirationTime);
-        return this;
-    }
-    
-    public ToStringHelper toStringHelper(Object self) {
-    	return MoreObjects.toStringHelper(self)
-    	        .add("id", id)
-    	        .add("user", user)
-    	        .add("requestTime", requestTime)
-    	        .add("expirationTime", expirationTime);
-    }
-    
-    @Override
-    public String toString() {
-    	return toStringHelper(this).toString();
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/SchedulerConfigurationData.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/SchedulerConfigurationData.java
deleted file mode 100644
index 58090b2..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/SchedulerConfigurationData.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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 javax.validation.constraints.NotNull;
-
-@Data
-public class SchedulerConfigurationData {
-	private final boolean enabled;
-	@NotNull
-	private final String cron;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectBudgetDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectBudgetDTO.java
deleted file mode 100644
index 472d34b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectBudgetDTO.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class UpdateProjectBudgetDTO {
-	@NotNull
-	private final String project;
-	@NotNull
-	private final Integer budget;
-	private final boolean monthlyBudget;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectDTO.java
deleted file mode 100644
index 4622ac5..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectDTO.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-import java.util.Set;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class UpdateProjectDTO {
-	@NotNull
-	private final String name;
-	@NotNull
-	private final Set<String> endpoints;
-	@NotNull
-	private final Set<String> groups;
-	@JsonProperty("shared_image_enabled")
-	private final boolean sharedImageEnabled;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/bundles/DlabKeycloakBundle.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/bundles/DlabKeycloakBundle.java
deleted file mode 100644
index b963160..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/bundles/DlabKeycloakBundle.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.dropwizard.bundles;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.auth.KeycloakAuthenticator;
-import com.epam.dlab.backendapi.auth.SelfServiceSecurityAuthorizer;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.google.inject.Inject;
-import de.ahus1.keycloak.dropwizard.KeycloakBundle;
-import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
-import io.dropwizard.auth.Authenticator;
-import io.dropwizard.auth.Authorizer;
-
-import java.security.Principal;
-
-public class DlabKeycloakBundle extends KeycloakBundle<SelfServiceApplicationConfiguration> {
-
-	@Inject
-	private KeycloakAuthenticator authenticator;
-
-	@Override
-	protected KeycloakConfiguration getKeycloakConfiguration(SelfServiceApplicationConfiguration configuration) {
-		return configuration.getKeycloakConfiguration();
-	}
-
-	@Override
-	protected Class<? extends Principal> getUserClass() {
-		return UserInfo.class;
-	}
-
-	@Override
-	protected Authorizer createAuthorizer() {
-		return new SelfServiceSecurityAuthorizer();
-	}
-
-	@Override
-	protected Authenticator createAuthenticator(KeycloakConfiguration configuration) {
-		return new KeycloakAuthenticator(configuration);
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/listeners/MongoStartupListener.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/listeners/MongoStartupListener.java
deleted file mode 100644
index d029e86..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/listeners/MongoStartupListener.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.dropwizard.listeners;
-
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.EndpointDAO;
-import com.epam.dlab.backendapi.dao.SettingsDAO;
-import com.epam.dlab.backendapi.dao.UserRoleDAO;
-import com.epam.dlab.backendapi.resources.dto.UserRoleDto;
-import com.epam.dlab.cloud.CloudProvider;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.inject.Inject;
-import io.dropwizard.lifecycle.ServerLifecycleListener;
-import lombok.extern.slf4j.Slf4j;
-import org.eclipse.jetty.server.Server;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-
-import static java.lang.String.format;
-import static java.util.Comparator.comparing;
-import static java.util.stream.Collectors.collectingAndThen;
-import static java.util.stream.Collectors.toCollection;
-
-
-@Slf4j
-public class MongoStartupListener implements ServerLifecycleListener {
-
-	private static final String ROLES_FILE_FORMAT = "/mongo/%s/mongo_roles.json";
-	private static final ObjectMapper MAPPER = new ObjectMapper();
-	private final UserRoleDAO userRoleDao;
-	private final SelfServiceApplicationConfiguration configuration;
-	private final SettingsDAO settingsDAO;
-	private final EndpointDAO endpointDAO;
-
-	@Inject
-	public MongoStartupListener(UserRoleDAO userRoleDao, SelfServiceApplicationConfiguration configuration,
-	                            SettingsDAO settingsDAO, EndpointDAO endpointDAO) {
-		this.userRoleDao = userRoleDao;
-		this.configuration = configuration;
-		this.settingsDAO = settingsDAO;
-		this.endpointDAO = endpointDAO;
-	}
-
-	@Override
-	public void serverStarted(Server server) {
-		settingsDAO.setServiceBaseName(configuration.getServiceBaseName());
-		settingsDAO.setConfOsFamily(configuration.getOs());
-		settingsDAO.setSsnInstanceSize(configuration.getSsnInstanceSize());
-		if (userRoleDao.findAll().isEmpty()) {
-			log.debug("Populating DLab roles into database");
-			userRoleDao.insert(getRoles());
-		} else {
-			log.info("Roles already populated. Do nothing ...");
-		}
-	}
-
-	private List<UserRoleDto> getRoles() {
-		Set<UserRoleDto> userRoles = new HashSet<>();
-		endpointDAO.getEndpoints().forEach(e -> userRoles.addAll(getUserRoleFromFile(e.getCloudProvider())));
-		return userRoles.stream().collect(collectingAndThen(toCollection(() -> new TreeSet<>(comparing(UserRoleDto::getId))),
-				ArrayList::new));
-	}
-
-	private List<UserRoleDto> getUserRoleFromFile(CloudProvider cloudProvider) {
-		try (InputStream is = getClass().getResourceAsStream(format(ROLES_FILE_FORMAT, cloudProvider.getName()))) {
-			return MAPPER.readValue(is, new TypeReference<List<UserRoleDto>>() {
-			});
-		} catch (IOException e) {
-			log.error("Can not marshall dlab roles due to: {}", e.getMessage(), e);
-			throw new IllegalStateException("Can not marshall dlab roles due to: " + e.getMessage());
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/listeners/RestoreHandlerStartupListener.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/listeners/RestoreHandlerStartupListener.java
deleted file mode 100644
index a92cae5..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/listeners/RestoreHandlerStartupListener.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.dropwizard.listeners;
-
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.rest.client.RESTService;
-import io.dropwizard.lifecycle.ServerLifecycleListener;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.eclipse.jetty.server.Server;
-
-@Slf4j
-public class RestoreHandlerStartupListener implements ServerLifecycleListener {
-
-	private final RESTService provisioningService;
-	private final EndpointService endpointService;
-
-	public RestoreHandlerStartupListener(RESTService provisioningService, EndpointService endpointService) {
-		this.provisioningService = provisioningService;
-		this.endpointService = endpointService;
-	}
-
-	@Override
-	public void serverStarted(Server server) {
-		try {
-			endpointService.getEndpointsWithStatus(EndpointDTO.EndpointStatus.ACTIVE)
-					.forEach(e -> provisioningService.post(e.getUrl() + "/handler/restore", StringUtils.EMPTY, Object.class));
-		} catch (Exception e) {
-			log.error("Exception occurred during restore handler request: {}", e.getMessage(), e);
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/healthcheck/MongoHealthCheck.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/healthcheck/MongoHealthCheck.java
deleted file mode 100644
index 5ce1b28..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/healthcheck/MongoHealthCheck.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.healthcheck;
-
-import com.codahale.metrics.health.HealthCheck;
-import com.epam.dlab.mongo.MongoService;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-public class MongoHealthCheck extends HealthCheck {
-	private final MongoService mongoService;
-
-	@Inject
-	public MongoHealthCheck(MongoService mongoService) {
-		this.mongoService = mongoService;
-	}
-
-	@Override
-	protected Result check() {
-		try {
-			mongoService.ping();
-		} catch (Exception e) {
-			log.error("Mongo is unavailable {}", e.getMessage(), e);
-			return Result.unhealthy(e.getMessage());
-		}
-		return Result.healthy();
-	}
-}
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
deleted file mode 100644
index 79b138b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/AuditInterceptor.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.Project;
-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.domain.AuditActionEnum;
-import com.epam.dlab.backendapi.domain.AuditDTO;
-import com.epam.dlab.backendapi.domain.AuditResourceTypeEnum;
-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 org.apache.commons.lang3.StringUtils;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.lang.reflect.Parameter;
-import java.util.Objects;
-import java.util.stream.IntStream;
-
-@Slf4j
-public class AuditInterceptor implements MethodInterceptor {
-    @Inject
-    private AuditService auditService;
-    @Inject
-    private SelfServiceApplicationConfiguration configuration;
-
-    @Override
-    public Object invoke(MethodInvocation mi) throws Throwable {
-        if (configuration.isAuditEnabled()) {
-            Method method = mi.getMethod();
-            final Parameter[] parameters = mi.getMethod().getParameters();
-            final String user = getUserInfo(mi, parameters);
-            final AuditActionEnum action = getAuditAction(method);
-            final AuditResourceTypeEnum resourceType = getResourceType(method);
-            final String project = getProject(mi, parameters);
-            final String resourceName = getResourceName(mi, parameters);
-            final String auditInfo = getInfo(mi, parameters);
-
-            AuditDTO auditCreateDTO = AuditDTO.builder()
-                    .user(user)
-                    .action(action)
-                    .type(resourceType)
-                    .project(project)
-                    .resourceName(resourceName)
-                    .info(auditInfo)
-                    .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 getAuditAction(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 AuditResourceTypeEnum getResourceType(Method method) {
-        Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
-        return IntStream.range(0, method.getDeclaredAnnotations().length)
-                .filter(i -> declaredAnnotations[i] instanceof Audit)
-                .mapToObj(i -> ((Audit) declaredAnnotations[i]).type())
-                .findAny()
-                .orElseThrow(() -> new DlabException("'Audit' annotation wanted!"));
-    }
-
-    private String getProject(MethodInvocation mi, Parameter[] parameters) {
-        return IntStream.range(0, parameters.length)
-                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(Project.class)))
-                .mapToObj(i -> (String) mi.getArguments()[i])
-                .findAny()
-                .orElse(StringUtils.EMPTY);
-    }
-
-    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()
-                .orElse(StringUtils.EMPTY);
-    }
-
-    private String getInfo(MethodInvocation mi, Parameter[] parameters) {
-        return IntStream.range(0, parameters.length)
-                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(Info.class)) && Objects.nonNull(mi.getArguments()[i]))
-                .mapToObj(i -> (String) mi.getArguments()[i])
-                .findAny()
-                .orElse(StringUtils.EMPTY);
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/BudgetLimitInterceptor.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/BudgetLimitInterceptor.java
deleted file mode 100644
index a9058bd..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/BudgetLimitInterceptor.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.backendapi.annotation.Project;
-import com.epam.dlab.backendapi.dao.BillingDAO;
-import com.epam.dlab.backendapi.service.BillingService;
-import com.epam.dlab.exceptions.ResourceQuoteReachedException;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-import org.aopalliance.intercept.MethodInterceptor;
-import org.aopalliance.intercept.MethodInvocation;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Parameter;
-import java.util.Objects;
-import java.util.stream.IntStream;
-
-@Slf4j
-public class BudgetLimitInterceptor implements MethodInterceptor {
-	@Inject
-	private BillingDAO billingDAO;
-	@Inject
-	private BillingService billingService;
-
-	@Override
-	public Object invoke(MethodInvocation mi) throws Throwable {
-		if (projectQuoteReached(mi) || billingDAO.isBillingQuoteReached()) {
-			final Method method = mi.getMethod();
-			log.warn("Execution of method {} failed because of reaching resource limit quote", method.getName());
-			throw new ResourceQuoteReachedException("Operation can not be finished. Resource quote is reached");
-		} else {
-			return mi.proceed();
-		}
-	}
-
-	private Boolean projectQuoteReached(MethodInvocation mi) {
-
-		final Parameter[] parameters = mi.getMethod().getParameters();
-		return IntStream.range(0, parameters.length)
-				.filter(i -> Objects.nonNull(parameters[i].getAnnotation(Project.class)))
-				.mapToObj(i -> (String) mi.getArguments()[i])
-				.findAny()
-				.map(billingService::isProjectQuoteReached)
-				.orElse(Boolean.FALSE);
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/ProjectAdminInterceptor.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/ProjectAdminInterceptor.java
deleted file mode 100644
index a536dab..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/ProjectAdminInterceptor.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.Project;
-import com.epam.dlab.backendapi.annotation.User;
-import com.epam.dlab.backendapi.roles.UserRoles;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceQuoteReachedException;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-import org.aopalliance.intercept.MethodInterceptor;
-import org.aopalliance.intercept.MethodInvocation;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Parameter;
-import java.util.Objects;
-import java.util.stream.IntStream;
-
-@Slf4j
-public class ProjectAdminInterceptor implements MethodInterceptor {
-    @Inject
-    private ProjectService projectService;
-
-    @Override
-    public Object invoke(MethodInvocation mi) throws Throwable {
-        if (grantAccess(mi)) {
-            return mi.proceed();
-        } else {
-            final Method method = mi.getMethod();
-            log.warn("Execution of method {} failed because user doesn't have appropriate permission", method.getName());
-            throw new ResourceQuoteReachedException("Operation can not be finished. User doesn't have appropriate permission");
-        }
-    }
-
-    private boolean grantAccess(MethodInvocation mi) {
-        final Parameter[] parameters = mi.getMethod().getParameters();
-        String project = IntStream.range(0, parameters.length)
-                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(Project.class)))
-                .mapToObj(i -> (String) mi.getArguments()[i])
-                .findAny()
-                .orElseThrow(() -> new DlabException("Project parameter wanted!"));
-        UserInfo userInfo = IntStream.range(0, parameters.length)
-                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(User.class)))
-                .mapToObj(i -> (UserInfo) mi.getArguments()[i])
-                .findAny()
-                .orElseThrow(() -> new DlabException("UserInfo parameter wanted!"));
-
-        return checkPermission(userInfo, project);
-    }
-
-    private boolean checkPermission(UserInfo userInfo, String project) {
-        return UserRoles.isAdmin(userInfo) || UserRoles.isProjectAdmin(userInfo, projectService.get(project).getGroups());
-    }
-}
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
deleted file mode 100644
index f49c98d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/CloudProviderModule.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.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;
-import com.epam.dlab.backendapi.resources.BucketResource;
-import com.epam.dlab.backendapi.resources.aws.ComputationalResourceAws;
-import com.epam.dlab.backendapi.resources.azure.ComputationalResourceAzure;
-import com.epam.dlab.backendapi.resources.gcp.ComputationalResourceGcp;
-import com.epam.dlab.backendapi.resources.gcp.GcpOauthResource;
-import com.epam.dlab.backendapi.service.BillingService;
-import com.epam.dlab.backendapi.service.InfrastructureInfoService;
-import com.epam.dlab.backendapi.service.InfrastructureTemplateService;
-import com.epam.dlab.backendapi.service.impl.BillingServiceImpl;
-import com.epam.dlab.backendapi.service.impl.InfrastructureInfoServiceImpl;
-import com.epam.dlab.backendapi.service.impl.InfrastructureTemplateServiceImpl;
-import com.epam.dlab.cloud.CloudModule;
-import com.epam.dlab.mongo.MongoServiceFactory;
-import com.fiestacabin.dropwizard.quartz.SchedulerConfiguration;
-import com.google.inject.Injector;
-import com.google.inject.Provides;
-import com.google.inject.Singleton;
-import io.dropwizard.setup.Environment;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
-import org.quartz.impl.StdSchedulerFactory;
-
-import static com.google.inject.matcher.Matchers.annotatedWith;
-import static com.google.inject.matcher.Matchers.any;
-
-public class CloudProviderModule extends CloudModule {
-
-    private static final String MONGO_URI_FORMAT = "mongodb://%s:%s@%s:%d/%s";
-    private static final String QUARTZ_MONGO_URI_PROPERTY = "org.quartz.jobStore.mongoUri";
-    private static final String QUARTZ_DB_NAME = "org.quartz.jobStore.dbName";
-
-    private SelfServiceApplicationConfiguration configuration;
-
-    public CloudProviderModule(SelfServiceApplicationConfiguration configuration) {
-        this.configuration = configuration;
-    }
-
-    @Override
-    protected void configure() {
-        bind(BillingService.class).to(BillingServiceImpl.class);
-        bind(InfrastructureInfoService.class).to(InfrastructureInfoServiceImpl.class);
-        bind(InfrastructureTemplateService.class).to(InfrastructureTemplateServiceImpl.class);
-        bind(SchedulerConfiguration.class).toInstance(
-                new SchedulerConfiguration(SelfServiceApplication.class.getPackage().getName()));
-
-        final BudgetLimitInterceptor budgetLimitInterceptor = new BudgetLimitInterceptor();
-        requestInjection(budgetLimitInterceptor);
-        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
-    public void init(Environment environment, Injector injector) {
-        environment.jersey().register(injector.getInstance(BillingResource.class));
-        environment.jersey().register(injector.getInstance(ComputationalResourceAws.class));
-        environment.jersey().register(injector.getInstance(ComputationalResourceAzure.class));
-        environment.jersey().register(injector.getInstance(ComputationalResourceGcp.class));
-        environment.jersey().register(injector.getInstance(BucketResource.class));
-        if (injector.getInstance(SelfServiceApplicationConfiguration.class).isGcpOuauth2AuthenticationEnabled()) {
-            environment.jersey().register(injector.getInstance(GcpOauthResource.class));
-        }
-    }
-
-    @Provides
-    @Singleton
-    Scheduler provideScheduler(SelfServiceApplicationConfiguration configuration) throws SchedulerException {
-        final MongoServiceFactory mongoFactory = configuration.getMongoFactory();
-        final String database = mongoFactory.getDatabase();
-        final String mongoUri = String.format(MONGO_URI_FORMAT, mongoFactory.getUsername(), mongoFactory.getPassword(),
-                mongoFactory.getHost(), mongoFactory.getPort(), database);
-        System.setProperty(QUARTZ_MONGO_URI_PROPERTY, mongoUri);
-        System.setProperty(QUARTZ_DB_NAME, database);
-        return StdSchedulerFactory.getDefaultScheduler();
-    }
-}
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
deleted file mode 100644
index c0c0912..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * 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.modules;
-
-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;
-import com.epam.dlab.backendapi.dao.BillingDAO;
-import com.epam.dlab.backendapi.dao.EndpointDAO;
-import com.epam.dlab.backendapi.dao.EndpointDAOImpl;
-import com.epam.dlab.backendapi.dao.ImageExploratoryDAO;
-import com.epam.dlab.backendapi.dao.ImageExploratoryDAOImpl;
-import com.epam.dlab.backendapi.dao.ProjectDAO;
-import com.epam.dlab.backendapi.dao.ProjectDAOImpl;
-import com.epam.dlab.backendapi.dao.UserGroupDAO;
-import com.epam.dlab.backendapi.dao.UserGroupDAOImpl;
-import com.epam.dlab.backendapi.dao.UserRoleDAO;
-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;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.EnvironmentService;
-import com.epam.dlab.backendapi.service.ExploratoryService;
-import com.epam.dlab.backendapi.service.ExternalLibraryService;
-import com.epam.dlab.backendapi.service.GitCredentialService;
-import com.epam.dlab.backendapi.service.GuacamoleService;
-import com.epam.dlab.backendapi.service.ImageExploratoryService;
-import com.epam.dlab.backendapi.service.InactivityService;
-import com.epam.dlab.backendapi.service.KeycloakService;
-import com.epam.dlab.backendapi.service.KeycloakServiceImpl;
-import com.epam.dlab.backendapi.service.LibraryService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.backendapi.service.ReuploadKeyService;
-import com.epam.dlab.backendapi.service.SchedulerJobService;
-import com.epam.dlab.backendapi.service.SecurityService;
-import com.epam.dlab.backendapi.service.SecurityServiceImpl;
-import com.epam.dlab.backendapi.service.SystemInfoService;
-import com.epam.dlab.backendapi.service.TagService;
-import com.epam.dlab.backendapi.service.TagServiceImpl;
-import com.epam.dlab.backendapi.service.UserGroupService;
-import com.epam.dlab.backendapi.service.UserRoleService;
-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;
-import com.epam.dlab.backendapi.service.impl.EndpointServiceImpl;
-import com.epam.dlab.backendapi.service.impl.EnvironmentServiceImpl;
-import com.epam.dlab.backendapi.service.impl.ExploratoryServiceImpl;
-import com.epam.dlab.backendapi.service.impl.GitCredentialServiceImpl;
-import com.epam.dlab.backendapi.service.impl.GuacamoleServiceImpl;
-import com.epam.dlab.backendapi.service.impl.ImageExploratoryServiceImpl;
-import com.epam.dlab.backendapi.service.impl.InactivityServiceImpl;
-import com.epam.dlab.backendapi.service.impl.LibraryServiceImpl;
-import com.epam.dlab.backendapi.service.impl.MavenCentralLibraryService;
-import com.epam.dlab.backendapi.service.impl.ProjectServiceImpl;
-import com.epam.dlab.backendapi.service.impl.ReuploadKeyServiceImpl;
-import com.epam.dlab.backendapi.service.impl.SchedulerJobServiceImpl;
-import com.epam.dlab.backendapi.service.impl.SystemInfoServiceImpl;
-import com.epam.dlab.backendapi.service.impl.UserGroupServiceImpl;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.mongo.MongoService;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.DockerAPI;
-import com.google.inject.name.Names;
-import io.dropwizard.auth.Authorizer;
-import io.dropwizard.client.JerseyClientBuilder;
-import io.dropwizard.setup.Environment;
-import org.eclipse.jetty.servlets.CrossOriginFilter;
-import org.glassfish.jersey.logging.LoggingFeature;
-
-import javax.servlet.DispatcherType;
-import javax.servlet.FilterRegistration;
-import javax.ws.rs.client.Client;
-import java.util.EnumSet;
-
-/**
- * Mock class for an application configuration of SelfService for developer mode.
- */
-public class DevModule extends ModuleBase<SelfServiceApplicationConfiguration> implements SecurityAPI, DockerAPI {
-
-	public static final String TOKEN = "token123";
-
-	/**
-	 * Instantiates an application configuration of SelfService for developer mode.
-	 *
-	 * @param configuration application configuration of SelfService.
-	 * @param environment   environment of SelfService.
-	 */
-	DevModule(SelfServiceApplicationConfiguration configuration, Environment environment) {
-		super(configuration, environment);
-	}
-
-	@Override
-	protected void configure() {
-		configureCors(environment);
-		final Client httpClient =
-				new JerseyClientBuilder(environment)
-						.using(configuration.getJerseyClientConfiguration())
-						.build("httpClient")
-						.register(new LoggingFeature());
-		bind(SecurityService.class).to(SecurityServiceImpl.class);
-		bind(KeycloakService.class).to(KeycloakServiceImpl.class);
-		bind(Client.class).toInstance(httpClient);
-		bind(SelfServiceApplicationConfiguration.class).toInstance(configuration);
-		bind(MongoService.class).toInstance(configuration.getMongoFactory().build(environment));
-		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.PROVISIONING_SERVICE_NAME))
-				.toInstance(configuration.getProvisioningFactory()
-						.build(environment, ServiceConsts.PROVISIONING_SERVICE_NAME));
-		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.BUCKET_SERVICE_NAME))
-				.toInstance(configuration.getBucketFactory()
-						.build(environment, ServiceConsts.BUCKET_SERVICE_NAME));
-		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.BILLING_SERVICE_NAME))
-				.toInstance(configuration.getBillingFactory()
-						.build(environment, ServiceConsts.BILLING_SERVICE_NAME));
-		bind(ImageExploratoryService.class).to(ImageExploratoryServiceImpl.class);
-		bind(ImageExploratoryDAO.class).to(ImageExploratoryDAOImpl.class);
-		bind(BackupService.class).to(BackupServiceImpl.class);
-		bind(BackupDAO.class).to(BackupDAOImpl.class);
-		bind(ExploratoryService.class).to(ExploratoryServiceImpl.class);
-		bind(TagService.class).to(TagServiceImpl.class);
-		bind(InactivityService.class).to(InactivityServiceImpl.class);
-		bind(Authorizer.class).to(SelfServiceSecurityAuthorizer.class);
-		bind(AccessKeyService.class).to(AccessKeyServiceImpl.class);
-		bind(GitCredentialService.class).to(GitCredentialServiceImpl.class);
-		bind(ComputationalService.class).to(ComputationalServiceImpl.class);
-		bind(LibraryService.class).to(LibraryServiceImpl.class);
-		bind(SchedulerJobService.class).to(SchedulerJobServiceImpl.class);
-		bind(EnvironmentService.class).to(EnvironmentServiceImpl.class);
-		bind(ReuploadKeyService.class).to(ReuploadKeyServiceImpl.class);
-		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.MAVEN_SEARCH_API))
-				.toInstance(configuration.getMavenApiFactory().build(environment, ServiceConsts.MAVEN_SEARCH_API));
-
-		bind(ExternalLibraryService.class).to(MavenCentralLibraryService.class);
-		bind(SystemInfoService.class).to(SystemInfoServiceImpl.class);
-		bind(UserGroupService.class).to(UserGroupServiceImpl.class);
-		bind(UserRoleService.class).to(UserRoleServiceImpl.class);
-		bind(UserRoleDAO.class).to(UserRoleDAOImpl.class);
-		bind(UserGroupDAO.class).to(UserGroupDAOImpl.class);
-		bind(ApplicationSettingService.class).to(ApplicationSettingServiceImpl.class);
-		bind(UserSettingService.class).to(UserSettingServiceImpl.class);
-		bind(GuacamoleService.class).to(GuacamoleServiceImpl.class);
-		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);
-	}
-
-	private void configureCors(Environment environment) {
-		final FilterRegistration.Dynamic cors =
-				environment.servlets().addFilter("CORS", CrossOriginFilter.class);
-
-		cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
-		cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin," +
-				"Authorization");
-		cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "OPTIONS,GET,PUT,POST,DELETE,HEAD");
-		cors.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "true");
-
-		cors.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
-
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ModuleFactory.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ModuleFactory.java
deleted file mode 100644
index eb8d3bc..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ModuleFactory.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.modules;
-
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.cloud.CloudModule;
-import com.google.inject.AbstractModule;
-import io.dropwizard.setup.Environment;
-
-public class ModuleFactory {
-
-	private ModuleFactory() {
-	}
-
-	/**
-	 * Instantiates an application configuration of SelfService for production or tests if
-	 * the mock property of configuration is set to <b>true</b> and method
-	 * {@link SelfServiceApplicationConfiguration#isMocked()}
-	 * returns <b>true</b> value.
-	 *
-	 * @param configuration application configuration of SelfService.
-	 * @param environment   environment of SelfService.
-	 */
-	public static AbstractModule getModule(SelfServiceApplicationConfiguration configuration, Environment
-			environment) {
-		return configuration.isDevMode()
-				? new DevModule(configuration, environment)
-				: new ProductionModule(configuration, environment);
-	}
-
-	public static CloudModule getCloudProviderModule(SelfServiceApplicationConfiguration configuration) {
-		return new CloudProviderModule(configuration);
-	}
-}
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
deleted file mode 100644
index 2581026..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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.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;
-import com.epam.dlab.backendapi.dao.BillingDAO;
-import com.epam.dlab.backendapi.dao.EndpointDAO;
-import com.epam.dlab.backendapi.dao.EndpointDAOImpl;
-import com.epam.dlab.backendapi.dao.ImageExploratoryDAO;
-import com.epam.dlab.backendapi.dao.ImageExploratoryDAOImpl;
-import com.epam.dlab.backendapi.dao.ProjectDAO;
-import com.epam.dlab.backendapi.dao.ProjectDAOImpl;
-import com.epam.dlab.backendapi.dao.UserGroupDAO;
-import com.epam.dlab.backendapi.dao.UserGroupDAOImpl;
-import com.epam.dlab.backendapi.dao.UserRoleDAO;
-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;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.EnvironmentService;
-import com.epam.dlab.backendapi.service.ExploratoryService;
-import com.epam.dlab.backendapi.service.ExternalLibraryService;
-import com.epam.dlab.backendapi.service.GitCredentialService;
-import com.epam.dlab.backendapi.service.GuacamoleService;
-import com.epam.dlab.backendapi.service.ImageExploratoryService;
-import com.epam.dlab.backendapi.service.InactivityService;
-import com.epam.dlab.backendapi.service.KeycloakService;
-import com.epam.dlab.backendapi.service.KeycloakServiceImpl;
-import com.epam.dlab.backendapi.service.LibraryService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.backendapi.service.ReuploadKeyService;
-import com.epam.dlab.backendapi.service.SchedulerJobService;
-import com.epam.dlab.backendapi.service.SecurityService;
-import com.epam.dlab.backendapi.service.SecurityServiceImpl;
-import com.epam.dlab.backendapi.service.SystemInfoService;
-import com.epam.dlab.backendapi.service.TagService;
-import com.epam.dlab.backendapi.service.TagServiceImpl;
-import com.epam.dlab.backendapi.service.UserGroupService;
-import com.epam.dlab.backendapi.service.UserRoleService;
-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;
-import com.epam.dlab.backendapi.service.impl.EndpointServiceImpl;
-import com.epam.dlab.backendapi.service.impl.EnvironmentServiceImpl;
-import com.epam.dlab.backendapi.service.impl.ExploratoryServiceImpl;
-import com.epam.dlab.backendapi.service.impl.GitCredentialServiceImpl;
-import com.epam.dlab.backendapi.service.impl.GuacamoleServiceImpl;
-import com.epam.dlab.backendapi.service.impl.ImageExploratoryServiceImpl;
-import com.epam.dlab.backendapi.service.impl.InactivityServiceImpl;
-import com.epam.dlab.backendapi.service.impl.LibraryServiceImpl;
-import com.epam.dlab.backendapi.service.impl.MavenCentralLibraryService;
-import com.epam.dlab.backendapi.service.impl.ProjectServiceImpl;
-import com.epam.dlab.backendapi.service.impl.ReuploadKeyServiceImpl;
-import com.epam.dlab.backendapi.service.impl.SchedulerJobServiceImpl;
-import com.epam.dlab.backendapi.service.impl.SystemInfoServiceImpl;
-import com.epam.dlab.backendapi.service.impl.UserGroupServiceImpl;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.mongo.MongoService;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.inject.name.Names;
-import io.dropwizard.auth.Authorizer;
-import io.dropwizard.client.JerseyClientBuilder;
-import io.dropwizard.setup.Environment;
-import org.glassfish.jersey.logging.LoggingFeature;
-
-import javax.ws.rs.client.Client;
-
-/**
- * Production class for an application configuration of SelfService.
- */
-public class ProductionModule extends ModuleBase<SelfServiceApplicationConfiguration> {
-
-	/**
-	 * Instantiates an application configuration of SelfService for production environment.
-	 *
-	 * @param configuration application configuration of SelfService.
-	 * @param environment   environment of SelfService.
-	 */
-	public ProductionModule(SelfServiceApplicationConfiguration configuration, Environment environment) {
-		super(configuration, environment);
-	}
-
-	@Override
-	protected void configure() {
-		final Client httpClient =
-				new JerseyClientBuilder(environment)
-						.using(configuration.getJerseyClientConfiguration())
-						.build("httpClient")
-						.register(new LoggingFeature());
-		bind(SelfServiceApplicationConfiguration.class).toInstance(configuration);
-		bind(MongoService.class).toInstance(configuration.getMongoFactory().build(environment));
-		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.SECURITY_SERVICE_NAME))
-				.toInstance(configuration.getSecurityFactory().build(environment, ServiceConsts
-						.SECURITY_SERVICE_NAME));
-		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.PROVISIONING_SERVICE_NAME))
-				.toInstance(configuration.getProvisioningFactory().build(environment, ServiceConsts
-						.PROVISIONING_SERVICE_NAME));
-		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.BUCKET_SERVICE_NAME))
-				.toInstance(configuration.getBucketFactory().build(environment, ServiceConsts
-						.BUCKET_SERVICE_NAME));
-		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.BILLING_SERVICE_NAME))
-				.toInstance(configuration.getBillingFactory()
-						.build(environment, ServiceConsts.BILLING_SERVICE_NAME));
-		bind(ImageExploratoryService.class).to(ImageExploratoryServiceImpl.class);
-		bind(ImageExploratoryDAO.class).to(ImageExploratoryDAOImpl.class);
-		bind(BackupService.class).to(BackupServiceImpl.class);
-		bind(BackupDAO.class).to(BackupDAOImpl.class);
-		bind(ExploratoryService.class).to(ExploratoryServiceImpl.class);
-		bind(Authorizer.class).to(SelfServiceSecurityAuthorizer.class);
-		bind(AccessKeyService.class).to(AccessKeyServiceImpl.class);
-		bind(GitCredentialService.class).to(GitCredentialServiceImpl.class);
-		bind(ComputationalService.class).to(ComputationalServiceImpl.class);
-		bind(LibraryService.class).to(LibraryServiceImpl.class);
-		bind(SchedulerJobService.class).to(SchedulerJobServiceImpl.class);
-		bind(EnvironmentService.class).to(EnvironmentServiceImpl.class);
-		bind(ReuploadKeyService.class).to(ReuploadKeyServiceImpl.class);
-		bind(RESTService.class).annotatedWith(Names.named(ServiceConsts.MAVEN_SEARCH_API))
-				.toInstance(configuration.getMavenApiFactory().build(environment, ServiceConsts.MAVEN_SEARCH_API));
-		bind(ExternalLibraryService.class).to(MavenCentralLibraryService.class);
-		bind(SystemInfoService.class).to(SystemInfoServiceImpl.class);
-		bind(UserGroupService.class).to(UserGroupServiceImpl.class);
-		bind(UserRoleService.class).to(UserRoleServiceImpl.class);
-		bind(UserRoleDAO.class).to(UserRoleDAOImpl.class);
-		bind(UserGroupDAO.class).to(UserGroupDAOImpl.class);
-		bind(InactivityService.class).to(InactivityServiceImpl.class);
-		bind(ApplicationSettingService.class).to(ApplicationSettingServiceImpl.class);
-		bind(UserSettingService.class).to(UserSettingServiceImpl.class);
-		bind(GuacamoleService.class).to(GuacamoleServiceImpl.class);
-		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);
-		bind(KeycloakService.class).to(KeycloakServiceImpl.class);
-		bind(Client.class).toInstance(httpClient);
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ApplicationSettingResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ApplicationSettingResource.java
deleted file mode 100644
index 92f079d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ApplicationSettingResource.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.ApplicationSettingService;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.annotation.security.RolesAllowed;
-import javax.validation.constraints.Min;
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-@Slf4j
-@Path("/settings")
-@RolesAllowed("/api/settings")
-public class ApplicationSettingResource {
-
-
-	private final ApplicationSettingService settingService;
-
-	@Inject
-	public ApplicationSettingResource(ApplicationSettingService settingService) {
-		this.settingService = settingService;
-	}
-
-	@PUT
-	@Path("budget/{maxBudgetAllowed}")
-	public Response setMaxBudget(@Auth UserInfo userInfo,
-								 @PathParam("maxBudgetAllowed") @Min(1) Long maxBudget) {
-		settingService.setMaxBudget(maxBudget);
-		return Response.noContent().build();
-	}
-
-	@DELETE
-	@Path("budget")
-	public Response removeAllowedBudget(@Auth UserInfo userInfo) {
-		log.debug("User {} is removing max budget application setting", userInfo.getName());
-		settingService.removeMaxBudget();
-		return Response.noContent().build();
-	}
-
-	@GET
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response getSettings(@Auth UserInfo userInfo) {
-		return Response.ok(settingService.getSettings()).build();
-
-	}
-}
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
deleted file mode 100644
index 188f80d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/AuditResource.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.AuditCreateDTO;
-import com.epam.dlab.backendapi.service.AuditService;
-import com.epam.dlab.model.StringList;
-import com.google.inject.Inject;
-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.QueryParam;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-@Path("/audit")
-public class AuditResource {
-    private final AuditService auditService;
-
-    @Inject
-    public AuditResource(AuditService auditService) {
-        this.auditService = auditService;
-    }
-
-    @POST
-    @Consumes(MediaType.APPLICATION_JSON)
-    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,
-                             @QueryParam("users") StringList users,
-                             @QueryParam("projects") StringList projects,
-                             @QueryParam("resource-names") StringList resourceNames,
-                             @QueryParam("resource-types") StringList resourceTypes,
-                             @QueryParam("date-start") String dateStart,
-                             @QueryParam("date-end") String dateEnd,
-                             @QueryParam("page-number") int pageNumber,
-                             @QueryParam("page-size") int pageSize) {
-        return Response
-                .ok(auditService.getAudit(users, projects, resourceNames, resourceTypes, dateStart, dateEnd, pageNumber, pageSize))
-                .build();
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BackupResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BackupResource.java
deleted file mode 100644
index 3f4125d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BackupResource.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.resources.dto.BackupFormDTO;
-import com.epam.dlab.backendapi.service.BackupService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.dto.backup.EnvBackupDTO;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.annotation.security.RolesAllowed;
-import javax.validation.Valid;
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.UUID;
-
-
-@Slf4j
-@Path("/infrastructure/backup")
-@RolesAllowed("/api/infrastructure/backup")
-public class BackupResource {
-
-	private final BackupService backupService;
-	private final RequestBuilder requestBuilder;
-	private final RequestId requestId;
-
-	@Inject
-	public BackupResource(BackupService backupService, RequestBuilder requestBuilder, RequestId requestId) {
-		this.backupService = backupService;
-		this.requestBuilder = requestBuilder;
-		this.requestId = requestId;
-	}
-
-	@POST
-	@Consumes(MediaType.APPLICATION_JSON)
-	@Produces(MediaType.TEXT_PLAIN)
-	public Response createBackup(@Auth UserInfo userInfo,
-								 @Valid BackupFormDTO backupFormDTO) {
-		log.debug("Creating backup for user {} with parameters {}", userInfo.getName(), backupFormDTO);
-		final EnvBackupDTO dto = requestBuilder.newBackupCreate(backupFormDTO, UUID.randomUUID().toString());
-		final String uuid = backupService.createBackup(dto, userInfo);
-		requestId.put(userInfo.getName(), uuid);
-		return Response.accepted(uuid).build();
-	}
-
-
-	@GET
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response getBackups(@Auth UserInfo userInfo) {
-		log.debug("Getting backups for user {}", userInfo.getName());
-		return Response.ok(backupService.getBackups(userInfo.getName())).build();
-	}
-
-	@GET
-	@Path("{id}")
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response getBackup(@Auth UserInfo userInfo,
-							  @PathParam("id") String id) {
-		log.debug("Getting backup with id {} for user {}", id, userInfo.getName());
-		return Response.ok(backupService.getBackup(userInfo.getName(), id)).build();
-	}
-
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BillingResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BillingResource.java
deleted file mode 100644
index a03edb3..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BillingResource.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.BillingFilter;
-import com.epam.dlab.backendapi.service.BillingService;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-@Path("/billing")
-@Consumes(MediaType.APPLICATION_JSON)
-public class BillingResource {
-
-    private final BillingService billingService;
-
-    @Inject
-    public BillingResource(BillingService billingService) {
-        this.billingService = billingService;
-    }
-
-    @GET
-    @Path("/quota")
-    @Produces(MediaType.APPLICATION_JSON)
-    public Response getQuota(@Auth UserInfo userInfo) {
-        return Response.ok(billingService.getQuotas(userInfo)).build();
-    }
-
-    @POST
-    @Path("/report")
-    @Produces(MediaType.APPLICATION_JSON)
-    public Response getBillingReport(@Auth UserInfo userInfo, @Valid @NotNull BillingFilter filter) {
-        return Response.ok(billingService.getBillingReport(userInfo, filter)).build();
-    }
-
-    @POST
-    @Path("/report/download")
-    @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    public Response downloadBillingReport(@Auth UserInfo userInfo, @Valid @NotNull BillingFilter filter) {
-        return Response.ok(billingService.downloadReport(userInfo, filter))
-                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"billing-report.csv\"")
-                .build();
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BucketResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BucketResource.java
deleted file mode 100644
index a23e1cc..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/BucketResource.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.BucketDeleteDTO;
-import com.epam.dlab.backendapi.resources.dto.FolderUploadDTO;
-import com.epam.dlab.backendapi.service.BucketService;
-import com.epam.dlab.exceptions.DlabException;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.fileupload.FileItemIterator;
-import org.apache.commons.fileupload.FileItemStream;
-import org.apache.commons.fileupload.servlet.ServletFileUpload;
-import org.apache.commons.fileupload.util.Streams;
-
-import javax.annotation.security.RolesAllowed;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-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.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.io.InputStream;
-import java.nio.file.Paths;
-
-@Path("/bucket")
-@Slf4j
-public class BucketResource {
-    private static final String AUDIT_FOLDER_UPLOAD_MESSAGE = "Upload folder: %s";
-    private static final String AUDIT_FILE_UPLOAD_MESSAGE = "Upload file: %s";
-    private static final String AUDIT_FILE_DOWNLOAD_MESSAGE = "Download file: %s";
-    private static final String AUDIT_FILE_DELETE_MESSAGE = "Delete file: %s";
-    private static final String OBJECT_FORM_FIELD = "object";
-    private static final String BUCKET_FORM_FIELD = "bucket";
-    private static final String ENDPOINT_FORM_FIELD = "endpoint";
-    private static final String SIZE_FORM_FIELD = "size";
-
-    private final BucketService bucketService;
-
-    @Inject
-    public BucketResource(BucketService bucketService) {
-        this.bucketService = bucketService;
-    }
-
-    @GET
-    @Path("/{bucket}/endpoint/{endpoint}")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    @RolesAllowed("/api/bucket/view")
-    public Response getListOfObjects(@Auth UserInfo userInfo,
-                                     @PathParam("bucket") String bucket,
-                                     @PathParam("endpoint") String endpoint) {
-        return Response.ok(bucketService.getObjects(userInfo, bucket, endpoint)).build();
-    }
-
-    @POST
-    @Path("/upload")
-    @Consumes(MediaType.MULTIPART_FORM_DATA)
-    @Produces(MediaType.APPLICATION_JSON)
-    @RolesAllowed("/api/bucket/upload")
-    public Response uploadObject(@Auth UserInfo userInfo, @Context HttpServletRequest request) {
-        upload(userInfo, request);
-        return Response.ok().build();
-    }
-
-    @POST
-    @Path("/folder/upload")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    @RolesAllowed("/api/bucket/upload")
-    public Response uploadFolder(@Auth UserInfo userInfo, @Valid FolderUploadDTO dto) {
-        bucketService.uploadFolder(userInfo, dto.getBucket(), dto.getFolder(), dto.getEndpoint(), String.format(AUDIT_FOLDER_UPLOAD_MESSAGE, dto.getFolder()));
-        return Response.ok().build();
-    }
-
-    @GET
-    @Path("/{bucket}/object/{object}/endpoint/{endpoint}/download")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    @RolesAllowed("/api/bucket/download")
-    public Response downloadObject(@Auth UserInfo userInfo, @Context HttpServletResponse resp,
-                                   @PathParam("bucket") String bucket,
-                                   @PathParam("object") String object,
-                                   @PathParam("endpoint") String endpoint) {
-        bucketService.downloadObject(userInfo, bucket, object, endpoint, resp, String.format(AUDIT_FILE_DOWNLOAD_MESSAGE, object));
-        return Response.ok()
-                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + Paths.get(object).getFileName() + "\"")
-                .build();
-    }
-
-    @POST
-    @Path("/objects/delete")
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    @RolesAllowed("/api/bucket/delete")
-    public Response deleteObject(@Auth UserInfo userInfo, @Valid BucketDeleteDTO bucketDto) {
-        final String listOfDeletedObject = String.join(", ", bucketDto.getObjects());
-        bucketService.deleteObjects(userInfo, bucketDto.getBucket(), bucketDto.getObjects(), bucketDto.getEndpoint(), String.format(AUDIT_FILE_DELETE_MESSAGE, listOfDeletedObject));
-        return Response.ok().build();
-    }
-
-    private void upload(UserInfo userInfo, HttpServletRequest request) {
-        String object = null;
-        String bucket = null;
-        String endpoint = null;
-        long fileSize = 0;
-
-        ServletFileUpload upload = new ServletFileUpload();
-        try {
-            FileItemIterator iterStream = upload.getItemIterator(request);
-            while (iterStream.hasNext()) {
-                FileItemStream item = iterStream.next();
-                try (InputStream stream = item.openStream()) {
-                    if (item.isFormField()) {
-                        if (OBJECT_FORM_FIELD.equals(item.getFieldName())) {
-                            object = Streams.asString(stream);
-                        } else if (BUCKET_FORM_FIELD.equals(item.getFieldName())) {
-                            bucket = Streams.asString(stream);
-                        } else if (ENDPOINT_FORM_FIELD.equals(item.getFieldName())) {
-                            endpoint = Streams.asString(stream);
-                        } else if (SIZE_FORM_FIELD.equals(item.getFieldName())) {
-                            fileSize = Long.parseLong(Streams.asString(stream));
-                        }
-                    } else {
-                        bucketService.uploadObject(userInfo, bucket, object, endpoint, stream, item.getContentType(), fileSize, String.format(AUDIT_FILE_UPLOAD_MESSAGE, object));
-                    }
-                } catch (Exception e) {
-                    log.error("Cannot upload object {} to bucket {}. {}", object, bucket, e.getMessage(), e);
-                    throw new DlabException(String.format("Cannot upload object %s to bucket %s. %s", object, bucket, e.getMessage()));
-                }
-            }
-        } catch (Exception e) {
-            log.error("User {} cannot upload object {} to bucket {}. {}", userInfo.getName(), object, bucket, e.getMessage(), e);
-            throw new DlabException(String.format("User %s cannot upload object %s to bucket %s. %s", userInfo.getName(), object, bucket, e.getMessage()));
-        }
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/EndpointResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/EndpointResource.java
deleted file mode 100644
index 7665831..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/EndpointResource.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.EndpointResourcesDTO;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.rest.dto.ErrorDTO;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.headers.Header;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-
-import javax.annotation.security.RolesAllowed;
-import javax.validation.Valid;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import java.net.URI;
-
-@Path("endpoint")
-@RolesAllowed("/api/endpoint")
-public class EndpointResource {
-
-	private final EndpointService endpointService;
-	@Context
-	private UriInfo uriInfo;
-
-	@Inject
-	public EndpointResource(EndpointService endpointService) {
-		this.endpointService = endpointService;
-	}
-
-	@Operation(summary = "Create endpoint", tags = "endpoint")
-	@ApiResponse(responseCode = "201", description = "Endpoint is successfully created",
-			headers =
-			@Header(required = true, name = "Location", description = "URI of created endpoint resource",
-					schema = @Schema(type = "string")))
-	@ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
-			MediaType.APPLICATION_JSON,
-			schema = @Schema(implementation = ErrorDTO.class)))
-	@ApiResponse(responseCode = "409", description = "Endpoint with passed name already exist in system",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON,
-					schema = @Schema(implementation = ErrorDTO.class)))
-	@Consumes(MediaType.APPLICATION_JSON)
-	@POST
-	public Response createEndpoint(@Parameter(hidden = true) @Auth UserInfo userInfo, @Valid EndpointDTO endpointDTO) {
-		endpointService.create(userInfo, endpointDTO.getName(), endpointDTO);
-		final URI uri = uriInfo.getRequestUriBuilder().path(endpointDTO.getName()).build();
-		return Response
-				.ok()
-				.location(uri)
-				.build();
-	}
-
-	@Operation(summary = "Get endpoint info", tags = "endpoint")
-	@ApiResponse(responseCode = "200", description = "Return information about endpoint",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
-			@Schema(implementation = EndpointDTO.class)))
-	@ApiResponse(responseCode = "404", description = "Endpoint with passed name not found",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON,
-					schema = @Schema(implementation = ErrorDTO.class)))
-	@GET
-	@Path("{name}")
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response getEndpoint(@Parameter(hidden = true) @Auth UserInfo userInfo,
-								@Parameter(description = "Endpoint name")
-								@PathParam("name") String name) {
-		return Response.ok(endpointService.get(name)).build();
-	}
-
-	@Operation(summary = "Get endpoints available in system", tags = "endpoint")
-	@ApiResponse(responseCode = "200", description = "Return information about endpoints",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
-			@Schema(implementation = EndpointDTO.class)))
-	@GET
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response getEndpoints(@Parameter(hidden = true) @Auth UserInfo userInfo) {
-		return Response.ok(endpointService.getEndpoints()).build();
-	}
-
-	@Operation(summary = "Get resources related to the endpoint", tags = "endpoint")
-	@ApiResponse(responseCode = "200", description = "Return information about resources of endpoint",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
-			@Schema(implementation = EndpointResourcesDTO.class)))
-	@GET
-	@Path("{name}/resources")
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response getEndpointResources(@Parameter(hidden = true) @Auth UserInfo userInfo,
-										 @Parameter(description = "Endpoint name")
-										 @PathParam("name") String name) {
-		return Response.ok(endpointService.getEndpointResources(name)).build();
-	}
-
-	@Operation(summary = "Remove endpoint", tags = "endpoint")
-	@ApiResponse(responseCode = "200", description = "Endpoint is successfully removed")
-	@ApiResponse(responseCode = "404", description = "Endpoint with passed name not found",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON,
-					schema = @Schema(implementation = ErrorDTO.class)))
-	@DELETE
-	@Path("{name}")
-	public Response removeEndpoint(@Parameter(hidden = true) @Auth UserInfo userInfo,
-								   @Parameter(description = "Endpoint name")
-								   @PathParam("name") String name) {
-		endpointService.remove(userInfo, name);
-		return Response.ok().build();
-	}
-
-	@Operation(summary = "Check whether endpoint url is valid", tags = "endpoint")
-	@ApiResponse(responseCode = "200", description = "Valid endpoint url")
-	@ApiResponse(responseCode = "404", description = "Endpoint url is not valid")
-	@GET
-	@Path("url/{url}")
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response checkEndpointUrl(@Parameter(hidden = true) @Auth UserInfo userInfo,
-									 @Parameter(description = "Endpoint url")
-									 @PathParam("url") String url) {
-		endpointService.checkUrl(userInfo, url);
-		return Response.ok().build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/EnvironmentResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/EnvironmentResource.java
deleted file mode 100644
index 3553ff4..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/EnvironmentResource.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.EnvironmentService;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-import org.hibernate.validator.constraints.NotEmpty;
-
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-@Path("environment")
-@Slf4j
-@RolesAllowed("environment/*")
-public class EnvironmentResource {
-
-	private EnvironmentService environmentService;
-
-	@Inject
-	public EnvironmentResource(EnvironmentService environmentService) {
-		this.environmentService = environmentService;
-	}
-
-	@GET
-	@Path("all")
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response getAllEnv(@Auth UserInfo userInfo) {
-		log.debug("Admin {} requested information about all user's environment", userInfo.getName());
-		return Response.ok(environmentService.getAllEnv(userInfo)).build();
-	}
-
-	@POST
-	@Consumes(MediaType.TEXT_PLAIN)
-	@Produces(MediaType.APPLICATION_JSON)
-	@Path("stop/{projectName}/{exploratoryName}")
-	public Response stopNotebook(@Auth UserInfo userInfo, @NotEmpty String user,
-								 @PathParam("projectName") String projectName,
-								 @PathParam("exploratoryName") String exploratoryName) {
-		log.info("Admin {} is stopping notebook {} of user {}", userInfo.getName(), exploratoryName, user);
-		environmentService.stopExploratory(userInfo, user, projectName, exploratoryName);
-		return Response.ok().build();
-	}
-
-	@POST
-	@Consumes(MediaType.TEXT_PLAIN)
-	@Produces(MediaType.APPLICATION_JSON)
-	@Path("stop/{projectName}/{exploratoryName}/{computationalName}")
-	public Response stopCluster(@Auth UserInfo userInfo, @NotEmpty String user,
-								@PathParam("projectName") String projectName,
-								@PathParam("exploratoryName") String exploratoryName,
-								@PathParam("computationalName") String computationalName) {
-		log.info("Admin {} is stopping computational resource {} affiliated with exploratory {} of user {}",
-				userInfo.getName(), computationalName, exploratoryName, user);
-		environmentService.stopComputational(userInfo, user, projectName, exploratoryName, computationalName);
-		return Response.ok().build();
-	}
-
-	@POST
-	@Consumes(MediaType.TEXT_PLAIN)
-	@Produces(MediaType.APPLICATION_JSON)
-	@Path("terminate/{projectName}/{exploratoryName}")
-	public Response terminateNotebook(@Auth UserInfo userInfo, @NotEmpty String user,
-									  @PathParam("projectName") String projectName,
-									  @PathParam("exploratoryName") String exploratoryName) {
-		log.info("Admin {} is terminating notebook {} of user {}", userInfo.getName(), exploratoryName, user);
-		environmentService.terminateExploratory(userInfo, user, projectName, exploratoryName);
-		return Response.ok().build();
-	}
-
-	@POST
-	@Consumes(MediaType.TEXT_PLAIN)
-	@Produces(MediaType.APPLICATION_JSON)
-	@Path("terminate/{projectName}/{exploratoryName}/{computationalName}")
-	public Response terminateCluster(@Auth UserInfo userInfo, @NotEmpty String user,
-									 @PathParam("projectName") String projectName,
-									 @PathParam("exploratoryName") String exploratoryName,
-									 @PathParam("computationalName") String computationalName) {
-		log.info("Admin {} is terminating computational resource {} affiliated with exploratory {} of user {}",
-				userInfo.getName(), computationalName, exploratoryName, user);
-		environmentService.terminateComputational(userInfo, user, projectName, exploratoryName, computationalName);
-		return Response.ok().build();
-	}
-}
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
deleted file mode 100644
index fd718b7..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ExploratoryResource.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.ExploratoryActionFormDTO;
-import com.epam.dlab.backendapi.resources.dto.ExploratoryCreateFormDTO;
-import com.epam.dlab.backendapi.roles.RoleType;
-import com.epam.dlab.backendapi.roles.UserRoles;
-import com.epam.dlab.backendapi.service.ExploratoryService;
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.model.exploratory.Exploratory;
-import com.epam.dlab.rest.contracts.ExploratoryAPI;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-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.List;
-
-/**
- * Provides the REST API for the exploratory.
- */
-@Path("/infrastructure_provision/exploratory_environment")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ExploratoryResource implements ExploratoryAPI {
-
-	private ExploratoryService exploratoryService;
-
-	@Inject
-	public ExploratoryResource(ExploratoryService exploratoryService) {
-		this.exploratoryService = exploratoryService;
-	}
-
-	@GET
-	public Response getExploratoryPopUp(@Auth UserInfo userInfo) {
-		return Response.ok(exploratoryService.getUserInstances(userInfo)).build();
-	}
-	/**
-	 * Creates the exploratory environment for user.
-	 *
-	 * @param userInfo user info.
-	 * @param formDTO  description for the exploratory environment.
-	 * @return {@link Response.Status#OK} request for provisioning service has been accepted.<br>
-	 * {@link Response.Status#FOUND} request for provisioning service has been duplicated.
-	 */
-	@PUT
-	public Response create(@Auth UserInfo userInfo,
-						   @Valid @NotNull ExploratoryCreateFormDTO formDTO) {
-		log.debug("Creating exploratory environment {} with name {} for user {}",
-				formDTO.getImage(), formDTO.getName(), userInfo.getName());
-		if (!UserRoles.checkAccess(userInfo, RoleType.EXPLORATORY, formDTO.getImage(), userInfo.getRoles())) {
-			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(), formDTO.getName());
-		return Response.ok(uuid).build();
-
-	}
-
-
-	/**
-	 * Starts exploratory environment for user.
-	 *
-	 * @param userInfo user info.
-	 * @param formDTO  description of exploratory action.
-	 * @return Invocation response as JSON string.
-	 */
-	@POST
-	public String start(@Auth UserInfo userInfo,
-						@Valid @NotNull ExploratoryActionFormDTO formDTO) {
-		log.debug("Starting exploratory environment {} for user {}", formDTO.getNotebookInstanceName(),
-				userInfo.getName());
-		return exploratoryService.start(userInfo, formDTO.getNotebookInstanceName(), formDTO.getProjectName(), null);
-	}
-
-	/**
-	 * Stops exploratory environment for user.
-	 *
-	 * @param userInfo user info.
-	 * @param name     name of exploratory environment.
-	 * @return Invocation response as JSON string.
-	 */
-	@DELETE
-	@Path("/{project}/{name}/stop")
-	public String stop(@Auth UserInfo userInfo,
-					   @PathParam("project") String project,
-					   @PathParam("name") String name) {
-		log.debug("Stopping exploratory environment {} for user {}", name, userInfo.getName());
-		return exploratoryService.stop(userInfo, userInfo.getName(), project, name, null);
-	}
-
-	/**
-	 * Terminates exploratory environment for user.
-	 *
-	 * @param userInfo user info.
-	 * @param name     name of exploratory environment.
-	 * @return Invocation response as JSON string.
-	 */
-	@DELETE
-	@Path("/{project}/{name}/terminate")
-	public String terminate(@Auth UserInfo userInfo,
-							@PathParam("project") String project,
-							@PathParam("name") String name) {
-		log.debug("Terminating exploratory environment {} for user {}", name, userInfo.getName());
-		return exploratoryService.terminate(userInfo, userInfo.getName(), project, name, null);
-	}
-
-	@PUT
-	@Path("/{project}/{name}/reconfigure")
-	public Response reconfigureSpark(@Auth UserInfo userInfo,
-									 @PathParam("project") String project,
-									 @PathParam("name") String name,
-									 List<ClusterConfig> config) {
-		log.debug("Updating exploratory {} spark cluster for user {}", name, userInfo.getName());
-		exploratoryService.updateClusterConfig(userInfo, project, name, config);
-		return Response.ok().build();
-	}
-
-	@GET
-	@Path("/{project}/{name}/cluster/config")
-	public Response getClusterConfig(@Auth UserInfo userInfo,
-									 @PathParam("project") String project,
-									 @PathParam("name") String name) {
-		log.debug("Getting exploratory {} spark cluster configuration for user {}", name, userInfo.getName());
-		return Response.ok(exploratoryService.getClusterConfig(userInfo, project, name)).build();
-	}
-
-	private Exploratory getExploratory(ExploratoryCreateFormDTO formDTO) {
-		return Exploratory.builder()
-				.name(formDTO.getName())
-				.dockerImage(formDTO.getImage())
-				.imageName(formDTO.getImageName())
-				.templateName(formDTO.getTemplateName())
-				.version(formDTO.getVersion())
-				.clusterConfig(formDTO.getClusterConfig())
-				.shape(formDTO.getShape())
-				.endpoint(formDTO.getEndpoint())
-				.project(formDTO.getProject())
-				.exploratoryTag(formDTO.getExploratoryTag())
-				.build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/GitCredsResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/GitCredsResource.java
deleted file mode 100644
index dd21b5b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/GitCredsResource.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.GitCredentialService;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsDTO;
-import com.epam.dlab.rest.contracts.ExploratoryAPI;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-/**
- * Provides the REST API for managing git credentials
- */
-@Path("/user/git_creds")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class GitCredsResource implements ExploratoryAPI {
-
-    private final GitCredentialService gitCredentialService;
-
-    @Inject
-    public GitCredsResource(GitCredentialService gitCredentialService) {
-        this.gitCredentialService = gitCredentialService;
-    }
-
-    /**
-     * Update GIT credentials for user.
-     *
-     * @param userInfo user info.
-     * @param formDTO  the list of credentials.
-     * @return {@link Response.Status#OK} request for provisioning service has been accepted.<br>
-     */
-    @PUT
-    public Response updateGitCreds(@Auth UserInfo userInfo, @Valid @NotNull ExploratoryGitCredsDTO formDTO) {
-        gitCredentialService.updateGitCredentials(userInfo, formDTO);
-        return Response.ok().build();
-    }
-
-	/**
-	 * Returns info about GIT credentials for user.
-	 *
-	 * @param userInfo user info.
-	 */
-	@GET
-	public ExploratoryGitCredsDTO getGitCreds(@Auth UserInfo userInfo) {
-		return gitCredentialService.getGitCredentials(userInfo.getName());
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ImageExploratoryResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ImageExploratoryResource.java
deleted file mode 100644
index e43f8c4..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ImageExploratoryResource.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.resources.dto.ExploratoryImageCreateFormDTO;
-import com.epam.dlab.backendapi.resources.dto.ImageInfoRecord;
-import com.epam.dlab.backendapi.service.ImageExploratoryService;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import java.net.URI;
-import java.util.List;
-
-/**
- * Manages images for exploratory and computational environment
- */
-@Path("/infrastructure_provision/exploratory_environment/image")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ImageExploratoryResource {
-	private static final String AUDIT_MESSAGE = "Create image: %s";
-
-	private final ImageExploratoryService imageExploratoryService;
-	private final RequestId requestId;
-
-	@Inject
-	public ImageExploratoryResource(ImageExploratoryService imageExploratoryService, RequestId requestId) {
-		this.imageExploratoryService = imageExploratoryService;
-		this.requestId = requestId;
-	}
-
-	@POST
-	public Response createImage(@Auth UserInfo ui,
-								@Valid @NotNull ExploratoryImageCreateFormDTO formDTO,
-								@Context UriInfo uriInfo) {
-		log.debug("Creating an image {} for user {}", formDTO, ui.getName());
-		String uuid = imageExploratoryService.createImage(ui, formDTO.getProjectName(), formDTO.getNotebookName(),
-				formDTO.getName(), formDTO.getDescription(), String.format(AUDIT_MESSAGE, formDTO.getName()));
-		requestId.put(ui.getName(), uuid);
-
-		final URI imageUri = UriBuilder.fromUri(uriInfo.getRequestUri())
-				.path(formDTO.getName())
-				.build();
-		return Response.accepted(uuid).location(imageUri).build();
-	}
-
-	@GET
-	public Response getImages(@Auth UserInfo ui,
-							  @QueryParam("docker_image") String dockerImage,
-							  @QueryParam("project") String project,
-							  @QueryParam("endpoint") String endpoint) {
-		log.debug("Getting images for user {}, project {}", ui.getName(), project);
-		final List<ImageInfoRecord> images = imageExploratoryService.getNotFailedImages(ui.getName(), dockerImage,
-				project, endpoint);
-		return Response.ok(images).build();
-	}
-
-	@GET
-	@Path("all")
-	public Response getAllImagesForProject(@Auth UserInfo ui, @NotNull @QueryParam("project") String project) {
-		log.debug("Getting images for user {}, project {}", ui.getName(), project);
-		final List<ImageInfoRecord> images = imageExploratoryService.getImagesForProject(project);
-		return Response.ok(images).build();
-	}
-
-	@GET
-	@Path("{name}")
-	public Response getImage(@Auth UserInfo ui,
-							 @PathParam("name") String name,
-							 @QueryParam("project") String project,
-							 @QueryParam("endpoint") String endpoint) {
-		log.debug("Getting image with name {} for user {}", name, ui.getName());
-		return Response.ok(imageExploratoryService.getImage(ui.getName(), name, project, endpoint)).build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResource.java
deleted file mode 100644
index deb9f96..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResource.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.HealthStatusPageDTO;
-import com.epam.dlab.backendapi.resources.dto.ProjectInfrastructureInfo;
-import com.epam.dlab.backendapi.service.InfrastructureInfoService;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.List;
-
-/**
- * Provides the REST API for the basic information about infrastructure.
- */
-@Path("/infrastructure")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class InfrastructureInfoResource {
-
-	private InfrastructureInfoService infrastructureInfoService;
-
-	@Inject
-	public InfrastructureInfoResource(InfrastructureInfoService infrastructureInfoService) {
-		this.infrastructureInfoService = infrastructureInfoService;
-	}
-
-	/**
-	 * Return status of self-service.
-	 */
-	@GET
-	public Response status() {
-		return Response.status(Response.Status.OK).build();
-	}
-
-	/**
-	 * Returns the status of infrastructure: edge.
-	 *
-	 * @param userInfo user info.
-	 */
-	@GET
-	@Path("/status")
-	public HealthStatusPageDTO status(@Auth UserInfo userInfo,
-									  @QueryParam("full") @DefaultValue("0") int fullReport) {
-		return infrastructureInfoService.getHeathStatus(userInfo);
-	}
-
-	/**
-	 * Returns the list of the provisioned user resources.
-	 *
-	 * @param userInfo user info.
-	 */
-	@GET
-	@Path("/info")
-	public List<ProjectInfrastructureInfo> getUserResources(@Auth UserInfo userInfo) {
-		return infrastructureInfoService.getUserResources(userInfo);
-
-	}
-
-	@GET
-	@Path("/meta")
-	public Response getVersion(@Auth UserInfo userInfo) {
-		return Response.ok(infrastructureInfoService.getInfrastructureMetaInfo())
-				.build();
-
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResource.java
deleted file mode 100644
index df85ff3..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResource.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.InfrastructureTemplateService;
-import com.epam.dlab.dto.base.computational.FullComputationalTemplate;
-import com.epam.dlab.dto.imagemetadata.ExploratoryMetadataDTO;
-import com.epam.dlab.rest.contracts.DockerAPI;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
-
-/**
- * Provides the REST API to retrieve exploratory/computational templates.
- */
-@Path("/infrastructure_templates")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class InfrastructureTemplateResource implements DockerAPI {
-
-	private InfrastructureTemplateService infrastructureTemplateService;
-
-	@Inject
-	public InfrastructureTemplateResource(InfrastructureTemplateService infrastructureTemplateService) {
-		this.infrastructureTemplateService = infrastructureTemplateService;
-	}
-
-	/**
-	 * Returns the list of the computational resources templates for user.
-	 *
-	 * @param userInfo user info.
-	 */
-	@GET
-	@Path("/{project}/{endpoint}/computational_templates")
-	public Iterable<FullComputationalTemplate> getComputationalTemplates(@Auth UserInfo userInfo,
-																		 @PathParam("project") String project,
-																		 @PathParam("endpoint") String endpoint) {
-		return infrastructureTemplateService.getComputationalTemplates(userInfo, project, endpoint);
-	}
-
-	/**
-	 * Returns the list of the exploratory environment templates for user.
-	 *
-	 * @param userInfo user info.
-	 */
-	@GET
-	@Path("/{project}/{endpoint}/exploratory_templates")
-	public Iterable<ExploratoryMetadataDTO> getExploratoryTemplates(@Auth UserInfo userInfo,
-																	@PathParam("project") String project,
-																	@PathParam("endpoint") String endpoint) {
-		return infrastructureTemplateService.getExploratoryTemplates(userInfo, project, endpoint);
-	}
-}
-
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/KeycloakResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/KeycloakResource.java
deleted file mode 100644
index 612a797..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/KeycloakResource.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.KeycloakConfiguration;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.SecurityDAO;
-import com.epam.dlab.backendapi.roles.UserRoles;
-import com.epam.dlab.backendapi.service.KeycloakService;
-import com.epam.dlab.backendapi.service.SecurityService;
-import com.epam.dlab.exceptions.DlabException;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-import org.keycloak.representations.AccessTokenResponse;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import static java.lang.String.format;
-
-@Path("/oauth")
-@Slf4j
-public class KeycloakResource {
-	private static final String LOGIN_URI_FORMAT = "%s/realms/%s/protocol/openid-connect/auth?client_id=%s" +
-			"&redirect_uri=%s&response_type=code";
-	private static final String KEYCLOAK_LOGOUT_URI_FORMAT = "%s/realms/%s/protocol/openid-connect/logout" +
-			"?redirect_uri=%s";
-	private final SecurityService securityService;
-	private final KeycloakService keycloakService;
-	private final SecurityDAO securityDAO;
-	private final String loginUri;
-	private final String logoutUri;
-	private final String redirectUri;
-	private final boolean defaultAccess;
-
-	@Inject
-	public KeycloakResource(SecurityService securityService, SelfServiceApplicationConfiguration configuration,
-	                        SecurityDAO securityDAO, KeycloakService keycloakService) {
-		this.securityDAO = securityDAO;
-		this.defaultAccess = configuration.getRoleDefaultAccess();
-		final KeycloakConfiguration keycloakConfiguration = configuration.getKeycloakConfiguration();
-		this.redirectUri = keycloakConfiguration.getRedirectUri();
-		this.securityService = securityService;
-		this.keycloakService = keycloakService;
-
-		loginUri = format(LOGIN_URI_FORMAT,
-				keycloakConfiguration.getAuthServerUrl(),
-				keycloakConfiguration.getRealm(),
-				keycloakConfiguration.getResource(),
-				redirectUri);
-		logoutUri = format(KEYCLOAK_LOGOUT_URI_FORMAT,
-				keycloakConfiguration.getAuthServerUrl(),
-				keycloakConfiguration.getRealm(),
-				redirectUri);
-	}
-
-	@GET
-	@Produces(MediaType.TEXT_PLAIN)
-	public Response getLoginUri() throws URISyntaxException {
-		return Response.ok(new URI(loginUri).toString())
-				.build();
-	}
-
-	@POST
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response getUser(@QueryParam("code") String code) {
-		return Response.ok(securityService.getUserInfo(code)).build();
-	}
-
-	@POST
-	@Path("/authorize")
-	public Response authorize(@Auth UserInfo userInfo) {
-		UserRoles.initialize(securityDAO, defaultAccess);
-		return Response.ok().build();
-	}
-
-	@GET
-	@Path("/logout")
-	public Response getLogoutUrl() throws URISyntaxException {
-		return Response.noContent()
-				.location(new URI(logoutUri))
-				.build();
-	}
-
-	@POST
-	@Path("/refresh/{refresh_token}")
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response refreshAccessToken(@PathParam("refresh_token") String refreshToken) throws URISyntaxException {
-		AccessTokenResponse tokenResponse;
-		try {
-			tokenResponse = keycloakService.generateAccessToken(refreshToken);
-		} catch (DlabException e) {
-			log.error("Cannot refresh token due to: {}", e.getMessage(), e);
-			return Response.status(Response.Status.BAD_REQUEST)
-					.location(new URI(logoutUri))
-					.build();
-		}
-		return Response.ok(new TokenInfo(tokenResponse.getToken(), tokenResponse.getRefreshToken())).build();
-	}
-
-	class TokenInfo {
-		@JsonProperty("access_token")
-		private final String accessToken;
-		@JsonProperty("refresh_token")
-		private final String refreshToken;
-
-		TokenInfo(String accessToken, String refreshToken) {
-			this.accessToken = accessToken;
-			this.refreshToken = refreshToken;
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/LibExploratoryResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/LibExploratoryResource.java
deleted file mode 100644
index 7adf447..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/LibExploratoryResource.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.domain.ExploratoryLibCache;
-import com.epam.dlab.backendapi.resources.dto.LibInfoRecord;
-import com.epam.dlab.backendapi.resources.dto.LibInstallFormDTO;
-import com.epam.dlab.backendapi.resources.dto.LibraryAutoCompleteDTO;
-import com.epam.dlab.backendapi.resources.dto.SearchLibsFormDTO;
-import com.epam.dlab.backendapi.service.ExternalLibraryService;
-import com.epam.dlab.backendapi.service.LibraryService;
-import com.epam.dlab.backendapi.validation.annotation.LibNameValid;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.exploratory.LibInstallDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.bson.Document;
-import org.hibernate.validator.constraints.NotBlank;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * Manages libraries for exploratory and computational environment
- */
-@Path("/infrastructure_provision/exploratory_environment")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class LibExploratoryResource {
-	private static final String AUDIT_MESSAGE = "Install libs: %s";
-
-	private final ExternalLibraryService externalLibraryService;
-	private final ExploratoryDAO exploratoryDAO;
-	private final LibraryService libraryService;
-
-	@Inject
-	public LibExploratoryResource(ExploratoryDAO exploratoryDAO, LibraryService libraryService,
-								  ExternalLibraryService externalLibraryService) {
-		this.exploratoryDAO = exploratoryDAO;
-		this.libraryService = libraryService;
-		this.externalLibraryService = externalLibraryService;
-	}
-
-	@GET
-	@Path("/lib-groups/exploratory")
-	public Response getExploratoryLibGroupList(@Auth UserInfo userInfo,
-	                                           @QueryParam("project") @NotBlank String projectName,
-	                                           @QueryParam("exploratory") @NotBlank String exploratoryName) {
-		return Response.ok(libraryService.getExploratoryLibGroups(userInfo, projectName, exploratoryName)).build();
-	}
-
-	@GET
-	@Path("/lib-groups/compute")
-	public Response getComputeLibGroupList(@Auth UserInfo userInfo) {
-		return Response.ok(libraryService.getComputeLibGroups()).build();
-	}
-
-	/**
-	 * Returns list of installed/failed libraries for dlab resource <code>exploratoryName<code/>
-	 * and <code>computationalName<code/> resource
-	 *
-	 * @param userInfo          user info
-	 * @param exploratoryName   name of exploratory resource
-	 * @param computationalName name of computational cluster
-	 * @return list of libraries
-	 */
-	@GET
-	@Path("/lib_list")
-	public List<Document> getLibList(@Auth UserInfo userInfo,
-									 @QueryParam("project_name") @NotBlank String projectName,
-									 @QueryParam("exploratory_name") @NotBlank String exploratoryName,
-									 @QueryParam("computational_name") String computationalName) {
-
-		log.debug("Loading list of libraries for user {} and exploratory {} and computational {}", userInfo.getName(),
-				exploratoryName, computationalName);
-		try {
-			return libraryService.getLibs(userInfo.getName(), projectName, exploratoryName, computationalName);
-
-		} catch (Exception t) {
-			log.error("Cannot load installed libraries for user {} and exploratory {} an", userInfo.getName(),
-					exploratoryName, t);
-			throw new DlabException("Cannot load installed libraries: " + t.getLocalizedMessage(), t);
-		}
-	}
-
-	/**
-	 * Returns formatted representation of installed libraries or libraries that were tried to be installed for
-	 * exploratory
-	 * and computational resources that relate to <code>exploratoryName<code/> exploratory resource with its's
-	 * statuses.
-	 *
-	 * @param userInfo        user info.
-	 * @param exploratoryName name of exploratory resource.
-	 * @return list of installed/failed libraries
-	 */
-	@GET
-	@Path("/lib_list/formatted")
-	public List<LibInfoRecord> getLibListFormatted(@Auth UserInfo userInfo,
-												   @QueryParam("project_name") @NotBlank String projectName,
-												   @QueryParam("exploratory_name") @NotBlank String exploratoryName) {
-
-		log.debug("Loading formatted list of libraries for user {} and exploratory {}", userInfo.getName(),
-				exploratoryName);
-		try {
-			return libraryService.getLibInfo(userInfo.getName(), projectName, exploratoryName);
-		} catch (Exception t) {
-			log.error("Cannot load list of libraries for user {} and exploratory {}", userInfo.getName(),
-					exploratoryName, t);
-			throw new DlabException("Cannot load  formatted list of installed libraries: " + t.getLocalizedMessage(),
-					t);
-		}
-	}
-
-	/**
-	 * Install libraries to the exploratory environment.
-	 *
-	 * @param userInfo user info.
-	 * @param formDTO  description of libraries which will be installed to the exploratory environment.
-	 * @return Invocation response as JSON string.
-	 */
-	@POST
-	@Path("/lib_install")
-	public Response libInstall(@Auth UserInfo userInfo,
-							   @Valid @NotNull LibInstallFormDTO formDTO) {
-		log.debug("Installing libs to environment {} for user {}", formDTO, userInfo.getName());
-		String project = formDTO.getProject();
-		final String exploratoryName = formDTO.getNotebookName();
-		final List<LibInstallDTO> libs = formDTO.getLibs();
-		final String computationalName = formDTO.getComputationalName();
-		final String auditInfo = getAuditInfo(libs);
-		String uuid = StringUtils.isEmpty(computationalName) ?
-				libraryService.installExploratoryLibs(userInfo, project, exploratoryName, libs, auditInfo) :
-				libraryService.installComputationalLibs(userInfo, project, exploratoryName, computationalName, libs, auditInfo);
-		return Response.ok(uuid)
-				.build();
-	}
-
-	/**
-	 * Returns the list of available libraries for exploratory basing on search conditions provided in @searchDTO.
-	 *
-	 * @param userInfo  user info.
-	 * @param searchDTO search condition for find libraries for the exploratory environment.
-	 * @return found libraries
-	 */
-	@POST
-	@Path("search/lib_list")
-	public Response getLibList(@Auth UserInfo userInfo,
-	                           @Valid @NotNull SearchLibsFormDTO searchDTO) {
-		try {
-			UserInstanceDTO userInstance;
-			if (StringUtils.isNotEmpty(searchDTO.getComputationalName())) {
-				userInstance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), searchDTO.getProjectName(),
-						searchDTO.getNotebookName(), searchDTO.getComputationalName());
-				userInstance.setResources(userInstance.getResources().stream()
-						.filter(e -> e.getComputationalName().equals(searchDTO.getComputationalName()))
-						.collect(Collectors.toList()));
-			} else {
-				userInstance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), searchDTO.getProjectName(), searchDTO.getNotebookName());
-			}
-
-			LibraryAutoCompleteDTO autoCompleteDTO = ExploratoryLibCache.getCache().getLibList(userInfo, userInstance, searchDTO.getGroup(), searchDTO.getStartWith());
-			return Response.ok(autoCompleteDTO).build();
-		} catch (Exception e) {
-			log.error("Cannot search libs for user {} with condition {}", userInfo.getName(), searchDTO, e);
-			throw new DlabException("Cannot search libraries: " + e.getLocalizedMessage(), e);
-		}
-	}
-
-
-	@GET
-	@Path("search/lib_list/maven")
-	public Response getMavenArtifactInfo(@Auth UserInfo userInfo,
-										 @LibNameValid @QueryParam("artifact") String artifact) {
-		final String[] libNameParts = artifact.split(":");
-		return Response.ok(externalLibraryService.getLibrary(libNameParts[0], libNameParts[1], libNameParts[2])).build();
-	}
-
-	private String getAuditInfo(List<LibInstallDTO> libs) {
-		return String.format(AUDIT_MESSAGE, libs
-				.stream()
-				.map(LibInstallDTO::getName)
-				.collect(Collectors.joining(", ")));
-	}
-}
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
deleted file mode 100644
index f1bca5f..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.BudgetDTO;
-import com.epam.dlab.backendapi.domain.CreateProjectDTO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.domain.ProjectEndpointDTO;
-import com.epam.dlab.backendapi.domain.UpdateProjectBudgetDTO;
-import com.epam.dlab.backendapi.domain.UpdateProjectDTO;
-import com.epam.dlab.backendapi.resources.dto.ProjectActionFormDTO;
-import com.epam.dlab.backendapi.service.AccessKeyService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.rest.dto.ErrorDTO;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.headers.Header;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-
-import javax.annotation.security.RolesAllowed;
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import java.net.URI;
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Path("project")
-public class ProjectResource {
-	private final ProjectService projectService;
-	private final AccessKeyService keyService;
-	@Context
-	private UriInfo uriInfo;
-
-	@Inject
-	public ProjectResource(ProjectService projectService, AccessKeyService keyService) {
-		this.projectService = projectService;
-		this.keyService = keyService;
-	}
-
-
-	@Operation(summary = "Create project", tags = "project")
-	@ApiResponse(responseCode = "201", description = "Project is successfully created",
-			headers =
-			@Header(required = true, name = "Location", description = "URI of created project resource",
-					schema = @Schema(type = "string")))
-	@ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
-			MediaType.APPLICATION_JSON,
-			schema = @Schema(implementation = ErrorDTO.class)))
-	@ApiResponse(responseCode = "409", description = "Project with passed name already exist in system",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON,
-					schema = @Schema(implementation = ErrorDTO.class)))
-	@POST
-	@Consumes(MediaType.APPLICATION_JSON)
-	@RolesAllowed("/api/project/create")
-	public Response createProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
-	                              @Valid CreateProjectDTO projectDTO) {
-		List<ProjectEndpointDTO> projectEndpointDTOS = projectDTO.getEndpoints()
-				.stream()
-				.map(e -> new ProjectEndpointDTO(e, UserInstanceStatus.CREATING, null))
-				.collect(Collectors.toList());
-		ProjectDTO project = new ProjectDTO(projectDTO.getName(), projectDTO.getGroups(), projectDTO.getKey(), projectDTO.getTag(),
-				new BudgetDTO(), projectEndpointDTOS, projectDTO.isSharedImageEnabled());
-		projectService.create(userInfo, project, projectDTO.getName());
-		final URI uri = uriInfo.getRequestUriBuilder().path(projectDTO.getName()).build();
-		return Response
-				.ok()
-				.location(uri)
-				.build();
-	}
-
-	@Operation(summary = "Start project", tags = "project")
-	@ApiResponse(responseCode = "202", description = "Project is starting")
-	@ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
-			MediaType.APPLICATION_JSON,
-			schema = @Schema(implementation = ErrorDTO.class)))
-	@Path("start")
-	@POST
-	@Consumes(MediaType.APPLICATION_JSON)
-	@RolesAllowed("/api/project")
-	public Response startProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
-	                             @NotNull @Valid ProjectActionFormDTO startProjectDto) {
-		projectService.start(userInfo, startProjectDto.getEndpoints(), startProjectDto.getProjectName());
-		return Response
-				.accepted()
-				.build();
-	}
-
-	@Operation(summary = "Stop project", tags = "project")
-	@ApiResponse(responseCode = "202", description = "Project is stopping")
-	@ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
-			MediaType.APPLICATION_JSON,
-			schema = @Schema(implementation = ErrorDTO.class)))
-	@Path("stop")
-	@POST
-	@Consumes(MediaType.APPLICATION_JSON)
-	@RolesAllowed("/api/project")
-	public Response stopProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
-	                            @NotNull @Valid ProjectActionFormDTO stopProjectDTO) {
-		projectService.stopWithResources(userInfo, stopProjectDTO.getEndpoints(), stopProjectDTO.getProjectName());
-		return Response
-				.accepted()
-				.build();
-	}
-
-	@Operation(summary = "Get project info", tags = "project")
-	@ApiResponse(responseCode = "200", description = "Return information about project",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
-			@Schema(implementation = ProjectDTO.class)))
-	@ApiResponse(responseCode = "404", description = "Project with passed name not found",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON,
-					schema = @Schema(implementation = ErrorDTO.class)))
-	@GET
-	@Path("{name}")
-	@Produces(MediaType.APPLICATION_JSON)
-	@RolesAllowed("/api/project")
-	public Response getProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
-	                           @Parameter(description = "Project name")
-	                           @PathParam("name") String name) {
-		return Response
-				.ok(projectService.get(name))
-				.build();
-	}
-
-	@Operation(summary = "Get available projects", tags = "project")
-	@ApiResponse(responseCode = "200", description = "Return information about projects",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
-			@Schema(implementation = ProjectDTO.class)))
-	@GET
-	@Produces(MediaType.APPLICATION_JSON)
-	@RolesAllowed("/api/project")
-	public Response getProjects(@Parameter(hidden = true) @Auth UserInfo userInfo) {
-		return Response
-				.ok(projectService.getProjects(userInfo))
-				.build();
-	}
-
-	@Operation(summary = "Get projects assigned to user", tags = "project")
-	@ApiResponse(responseCode = "200", description = "Return information about projects",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
-			@Schema(implementation = ProjectDTO.class)))
-	@GET
-	@Path("/me")
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response getUserProjects(@Parameter(hidden = true) @Auth UserInfo userInfo,
-	                                @QueryParam("active") @DefaultValue("false") boolean active) {
-		return Response
-				.ok(projectService.getUserProjects(userInfo, active))
-				.build();
-	}
-
-	@Operation(summary = "Update project", tags = "project")
-	@ApiResponse(responseCode = "200", description = "Project is successfully updated")
-	@ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
-			MediaType.APPLICATION_JSON,
-			schema = @Schema(implementation = ErrorDTO.class)))
-	@ApiResponse(responseCode = "404", description = "Project with passed name not found",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON,
-					schema = @Schema(implementation = ErrorDTO.class)))
-	@PUT
-	@RolesAllowed("/api/project")
-	public Response updateProject(@Parameter(hidden = true) @Auth UserInfo userInfo, UpdateProjectDTO projectDTO) {
-		projectService.update(userInfo, projectDTO, projectDTO.getName());
-		return Response.ok().build();
-	}
-
-	@Operation(summary = "Remove project", tags = "project")
-	@ApiResponse(responseCode = "200", description = "Project is successfully removed")
-	@ApiResponse(responseCode = "404", description = "Project with passed name not found",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON,
-					schema = @Schema(implementation = ErrorDTO.class)))
-	@POST
-	@Path("terminate")
-	@RolesAllowed("/api/project")
-	public Response removeProjectEndpoint(@Parameter(hidden = true) @Auth UserInfo userInfo,
-	                                      @NotNull @Valid ProjectActionFormDTO projectActionDTO) {
-		projectService.terminateEndpoint(userInfo, projectActionDTO.getEndpoints(), projectActionDTO.getProjectName());
-		return Response.ok().build();
-	}
-
-	@Operation(summary = "Updates project budget", tags = "project")
-	@ApiResponse(responseCode = "200", description = "Project budget is successfully updated")
-	@ApiResponse(responseCode = "404", description = "Project with specified name not found")
-	@ApiResponse(responseCode = "400", description = "Validation error",
-			content = @Content(mediaType = MediaType.APPLICATION_JSON,
-					schema = @Schema(implementation = ErrorDTO.class)))
-	@PUT
-	@Path("/budget")
-	@RolesAllowed("/api/project")
-	public Response updateBudget(
-			@Parameter(hidden = true) @Auth UserInfo userInfo,
-			@Parameter(description = "Update project budgets list") List<UpdateProjectBudgetDTO> dtos) {
-		projectService.updateBudget(userInfo, dtos);
-		return Response.ok().build();
-	}
-
-	@Operation(summary = "Generate keys for project", tags = "project")
-	@ApiResponse(responseCode = "200", description = "Keys are successfully generated")
-	@POST
-	@Path("/keys")
-	@Consumes(MediaType.APPLICATION_JSON)
-	@Produces(MediaType.APPLICATION_JSON)
-	@RolesAllowed("/api/project")
-	public Response generate(@Parameter(hidden = true) @Auth UserInfo userInfo) {
-		return Response
-				.ok(keyService.generateKeys(userInfo))
-				.build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/SchedulerJobResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/SchedulerJobResource.java
deleted file mode 100644
index f34897f..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/SchedulerJobResource.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.SchedulerJobService;
-import com.epam.dlab.backendapi.validation.annotation.SchedulerJobDTOValid;
-import com.epam.dlab.dto.SchedulerJobDTO;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-/**
- * Manages scheduler jobs for exploratory environment
- */
-@Path("/infrastructure_provision/exploratory_environment/scheduler")
-@Slf4j
-public class SchedulerJobResource {
-
-	private SchedulerJobService schedulerJobService;
-
-	@Inject
-	public SchedulerJobResource(SchedulerJobService schedulerJobService) {
-		this.schedulerJobService = schedulerJobService;
-	}
-
-
-	/**
-	 * Updates exploratory <code>exploratoryName<code/> for user <code>userInfo<code/> with new scheduler job data
-	 *
-	 * @param userInfo        user info
-	 * @param exploratoryName name of exploratory resource
-	 * @param dto             scheduler job data
-	 * @return response
-	 */
-	@POST
-	@Path("/{projectName}/{exploratoryName}")
-	@Consumes(MediaType.APPLICATION_JSON)
-	public Response updateExploratoryScheduler(@Auth UserInfo userInfo,
-											   @PathParam("projectName") String projectName,
-											   @PathParam("exploratoryName") String exploratoryName,
-											   @SchedulerJobDTOValid SchedulerJobDTO dto) {
-		schedulerJobService.updateExploratorySchedulerData(userInfo, projectName, exploratoryName, dto);
-		return Response.ok().build();
-	}
-
-	/**
-	 * Removes exploratory <code>exploratoryName<code/> for user <code>userInfo<code/>
-	 *
-	 * @param userInfo        user info
-	 * @param exploratoryName name of exploratory resource
-	 * @return response
-	 */
-	@DELETE
-	@Path("/{exploratoryName}")
-	public Response removeExploratoryScheduler(@Auth UserInfo userInfo,
-											   @PathParam("exploratoryName") String exploratoryName) {
-		log.debug("User {} is trying to remove scheduler for exploratory {}", userInfo.getName(), exploratoryName);
-		schedulerJobService.removeScheduler(userInfo.getName(), exploratoryName);
-		return Response.ok().build();
-	}
-
-	/**
-	 * Updates computational resource <code>computationalName<code/> affiliated with exploratory
-	 * <code>exploratoryName<code/> for user <code>userInfo<code/> with new scheduler job data
-	 *
-	 * @param userInfo          user info
-	 * @param exploratoryName   name of exploratory resource
-	 * @param computationalName name of computational resource
-	 * @param dto               scheduler job data
-	 * @return response
-	 */
-	@POST
-	@Path("/{projectName}/{exploratoryName}/{computationalName}")
-	@Consumes(MediaType.APPLICATION_JSON)
-	public Response updateComputationalScheduler(@Auth UserInfo userInfo,
-												 @PathParam("projectName") String projectName,
-												 @PathParam("exploratoryName") String exploratoryName,
-												 @PathParam("computationalName") String computationalName,
-												 @SchedulerJobDTOValid SchedulerJobDTO dto) {
-		schedulerJobService.updateComputationalSchedulerData(userInfo, projectName, exploratoryName, computationalName, dto);
-		return Response.ok().build();
-	}
-
-	/**
-	 * Updates computational resource <code>computationalName<code/> affiliated with exploratory
-	 * <code>exploratoryName<code/> for user <code>userInfo<code/> with new scheduler job data
-	 *
-	 * @param userInfo          user info
-	 * @param exploratoryName   name of exploratory resource
-	 * @param computationalName name of computational resource
-	 * @return response
-	 */
-	@DELETE
-	@Path("/{exploratoryName}/{computationalName}")
-	public Response removeComputationalScheduler(@Auth UserInfo userInfo,
-												 @PathParam("exploratoryName") String exploratoryName,
-												 @PathParam("computationalName") String computationalName) {
-		log.debug("User {} is trying to remove scheduler for computational {} connected with exploratory {}",
-				userInfo.getName(), computationalName, exploratoryName);
-		schedulerJobService.removeScheduler(userInfo.getName(), exploratoryName, computationalName);
-		return Response.ok().build();
-	}
-
-
-	/**
-	 * Returns scheduler job for exploratory resource <code>exploratoryName<code/>
-	 *
-	 * @param userInfo        user info
-	 * @param exploratoryName name of exploratory resource
-	 * @return scheduler job data
-	 */
-	@GET
-	@Path("/{projectName}/{exploratoryName}")
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response fetchSchedulerJobForUserAndExploratory(@Auth UserInfo userInfo,
-														   @PathParam("projectName") String projectName,
-														   @PathParam("exploratoryName") String exploratoryName) {
-		log.debug("Loading scheduler job for user {} and exploratory {}...", userInfo.getName(), exploratoryName);
-		final SchedulerJobDTO schedulerJob =
-				schedulerJobService.fetchSchedulerJobForUserAndExploratory(userInfo.getName(), projectName, exploratoryName);
-		return Response.ok(schedulerJob).build();
-	}
-
-	/**
-	 * Returns scheduler job for computational resource <code>computationalName<code/> affiliated with
-	 * exploratory <code>exploratoryName<code/>
-	 *
-	 * @param userInfo          user info
-	 * @param exploratoryName   name of exploratory resource
-	 * @param computationalName name of computational resource
-	 * @return scheduler job data
-	 */
-	@GET
-	@Path("/{projectName}/{exploratoryName}/{computationalName}")
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response fetchSchedulerJobForComputationalResource(@Auth UserInfo userInfo,
-															  @PathParam("exploratoryName") String exploratoryName,
-															  @PathParam("projectName") String projectName,
-															  @PathParam("computationalName") String computationalName) {
-		log.debug("Loading scheduler job for user {}, exploratory {} and computational resource {}...",
-				userInfo.getName(), exploratoryName, computationalName);
-		final SchedulerJobDTO schedulerJob = schedulerJobService
-				.fetchSchedulerJobForComputationalResource(userInfo.getName(), projectName, exploratoryName, computationalName);
-		return Response.ok(schedulerJob).build();
-	}
-
-	@GET
-	@Path("active")
-	@Produces(MediaType.APPLICATION_JSON)
-	public Response getActiveSchedulers(@Auth UserInfo userInfo,
-										@QueryParam("minuteOffset") long minuteOffset) {
-		log.trace("Getting active schedulers for user {} and offset {}", userInfo.getName(), minuteOffset);
-		return Response.ok(schedulerJobService.getActiveSchedulers(userInfo.getName(), minuteOffset)).build();
-	}
-
-}
-
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/SystemInfoResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/SystemInfoResource.java
deleted file mode 100644
index 9e646d0..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/SystemInfoResource.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.SystemInfoDto;
-import com.epam.dlab.backendapi.service.SystemInfoService;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-@Slf4j
-@Path("sysinfo")
-@Produces(MediaType.APPLICATION_JSON)
-@RolesAllowed("sysinfo")
-public class SystemInfoResource {
-
-	private SystemInfoService systemInfoService;
-
-	@Inject
-	public SystemInfoResource(SystemInfoService systemInfoService) {
-		this.systemInfoService = systemInfoService;
-	}
-
-
-	@GET
-
-	public Response getSystemInfo(@Auth UserInfo userInfo) {
-		log.debug("Getting system info for user {}...", userInfo.getName());
-		final SystemInfoDto systemInfoDto = systemInfoService.getSystemInfo();
-		return Response.ok(systemInfoDto).build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/UserGroupResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/UserGroupResource.java
deleted file mode 100644
index 06a4a77..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/UserGroupResource.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.GroupDTO;
-import com.epam.dlab.backendapi.resources.dto.UpdateGroupDTO;
-import com.epam.dlab.backendapi.service.UserGroupService;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.annotation.security.RolesAllowed;
-import javax.validation.Valid;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-@Slf4j
-@Path("group")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class UserGroupResource {
-
-	private final UserGroupService userGroupService;
-
-	@Inject
-	public UserGroupResource(UserGroupService userGroupService) {
-		this.userGroupService = userGroupService;
-	}
-
-
-	@POST
-	@RolesAllowed("/roleManagement/create")
-	public Response createGroup(@Auth UserInfo userInfo, @Valid GroupDTO dto) {
-		log.debug("Creating new group {}", dto.getName());
-		userGroupService.createGroup(userInfo, dto.getName(), dto.getRoleIds().keySet(), dto.getUsers());
-		return Response.ok().build();
-	}
-
-	@PUT
-	@RolesAllowed("/roleManagement")
-	public Response updateGroup(@Auth UserInfo userInfo, @Valid UpdateGroupDTO dto) {
-		log.debug("Updating group {}", dto.getName());
-		userGroupService.updateGroup(userInfo, dto.getName(), dto.getRoles(), dto.getUsers());
-		return Response.ok().build();
-	}
-
-	@GET
-	@RolesAllowed("/roleManagement")
-	public Response getGroups(@Auth UserInfo userInfo) {
-		log.debug("Getting all groups for admin {}...", userInfo.getName());
-		return Response.ok(userGroupService.getAggregatedRolesByGroup(userInfo)).build();
-	}
-
-	@DELETE
-	@Path("{id}")
-	@RolesAllowed("/roleManagement/delete")
-	public Response deleteGroup(@Auth UserInfo userInfo, @PathParam("id") String group) {
-		log.info("Admin {} is trying to delete group {} from application", userInfo.getName(), group);
-		userGroupService.removeGroup(userInfo, group);
-		return Response.ok().build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/UserRoleResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/UserRoleResource.java
deleted file mode 100644
index 52ad739..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/UserRoleResource.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.UserRoleDto;
-import com.epam.dlab.backendapi.service.UserRoleService;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.annotation.security.RolesAllowed;
-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;
-
-@Slf4j
-@Path("role")
-@RolesAllowed("/roleManagement")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class UserRoleResource {
-
-	private final UserRoleService userRoleService;
-
-	@Inject
-	public UserRoleResource(UserRoleService roleService) {
-		this.userRoleService = roleService;
-	}
-
-	@GET
-	public Response getRoles(@Auth UserInfo userInfo) {
-		log.debug("Getting all roles for admin {}...", userInfo.getName());
-		return Response.ok(userRoleService.getUserRoles()).build();
-	}
-
-	@POST
-	public Response createRole(@Auth UserInfo userInfo, UserRoleDto dto) {
-		log.info("Creating new role {} on behalf of admin {}...", dto, userInfo.getName());
-		userRoleService.createRole(dto);
-		return Response.ok().build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/UserSettingsResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/UserSettingsResource.java
deleted file mode 100644
index a32dad8..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/UserSettingsResource.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.UserDTO;
-import com.epam.dlab.backendapi.service.UserSettingService;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import org.hibernate.validator.constraints.NotBlank;
-import org.hibernate.validator.constraints.NotEmpty;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.annotation.security.RolesAllowed;
-import javax.validation.Valid;
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.List;
-
-
-@Path("/user/settings")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class UserSettingsResource {
-	private static final Logger LOGGER = LoggerFactory.getLogger(UserSettingsResource.class);
-
-	private UserSettingService userSettingService;
-
-	@Inject
-	public UserSettingsResource(UserSettingService userSettingService) {
-		this.userSettingService = userSettingService;
-	}
-
-	@GET
-	public String getSettings(@Auth UserInfo userInfo) {
-		String settings = userSettingService.getUISettings(userInfo);
-		LOGGER.debug("Returns settings for user {}, content is {}", userInfo.getName(), settings);
-		return settings;
-	}
-
-	@POST
-	public Response saveSettings(@Auth UserInfo userInfo,
-								 @NotBlank String settings) {
-		LOGGER.debug("Saves settings for user {}, content is {}", userInfo.getName(), settings);
-		userSettingService.saveUISettings(userInfo, settings);
-		return Response.ok().build();
-	}
-
-	@PUT
-	@Path("budget")
-	@RolesAllowed("/user/settings")
-	public Response updateUsersBudget(@Auth UserInfo userInfo,
-									  @Valid @NotEmpty List<UserDTO> budgets) {
-		LOGGER.debug("User {} is updating allowed budget for users: {}", userInfo.getName(), budgets);
-		userSettingService.updateUsersBudget(budgets);
-		return Response.ok().build();
-	}
-
-
-}
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
deleted file mode 100644
index dc964fc..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ComputationalResourceAws.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * 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.resources.aws;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
-import com.epam.dlab.backendapi.resources.dto.aws.AwsComputationalCreateForm;
-import com.epam.dlab.backendapi.roles.RoleType;
-import com.epam.dlab.backendapi.roles.UserRoles;
-import com.epam.dlab.backendapi.service.ComputationalService;
-import com.epam.dlab.dto.aws.computational.AwsComputationalResource;
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.contracts.ComputationalAPI;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import io.swagger.v3.oas.annotations.Parameter;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-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.List;
-
-import static com.epam.dlab.dto.UserInstanceStatus.CREATING;
-import static com.epam.dlab.dto.base.DataEngineType.SPARK_STANDALONE;
-
-
-/**
- * Provides the REST API for the computational resource on AWS.
- */
-@Path("/aws/infrastructure_provision/computational_resources")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ComputationalResourceAws implements ComputationalAPI {
-	@Inject
-	private SelfServiceApplicationConfiguration configuration;
-	@Inject
-	private ComputationalService computationalService;
-
-	@GET
-	@Path("/{project}/{endpoint}/templates")
-	public Response getTemplates(@Auth @Parameter(hidden = true) UserInfo userInfo, @PathParam("project") String project,
-								 @PathParam("endpoint") String endpoint) {
-		return Response.ok(computationalService.getComputationalNamesAndTemplates(userInfo, project, endpoint)).build();
-	}
-
-	/**
-	 * Asynchronously creates EMR cluster
-	 *
-	 * @param userInfo user info.
-	 * @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
-	 */
-	@PUT
-	@Path("dataengine-service")
-	public Response createDataEngineService(@Auth @Parameter(hidden = true) UserInfo userInfo,
-											@Parameter @Valid @NotNull AwsComputationalCreateForm form) {
-
-		log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
-
-		if (DataEngineType.CLOUD_SERVICE == DataEngineType.fromDockerImageName(form.getImage())) {
-
-			validate(userInfo, form);
-
-			AwsComputationalResource awsComputationalResource = AwsComputationalResource.builder()
-					.computationalName(form.getName())
-					.imageName(form.getImage())
-					.templateName(form.getTemplateName())
-					.status(CREATING.toString())
-					.masterShape(form.getMasterInstanceType())
-					.slaveShape(form.getSlaveInstanceType())
-					.slaveSpot(form.getSlaveInstanceSpot())
-					.slaveSpotPctPrice(form.getSlaveInstanceSpotPctPrice())
-					.slaveNumber(form.getInstanceCount())
-					.config(form.getConfig())
-					.version(form.getVersion())
-					.totalInstanceCount(Integer.parseInt(form.getInstanceCount()))
-                    .build();
-            boolean resourceAdded = computationalService.createDataEngineService(userInfo, form.getName(), form, awsComputationalResource,
-                    form.getProject(), getAuditInfo(form.getNotebookName()));
-			return resourceAdded ? Response.ok().build() : Response.status(Response.Status.FOUND).build();
-		}
-
-		throw new IllegalArgumentException("Malformed image " + form.getImage());
-	}
-
-	/**
-	 * Asynchronously triggers creation of Spark cluster
-	 *
-	 * @param userInfo user info.
-	 * @param form     DTO info about creation of the computational resource.
-	 * @return 200 OK - if request success, 302 Found - for duplicates.
-	 */
-
-	@PUT
-	@Path("dataengine")
-	public Response createDataEngine(@Auth UserInfo userInfo,
-									 @Valid @NotNull SparkStandaloneClusterCreateForm form) {
-        log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
-
-        validate(form);
-        return computationalService.createSparkCluster(userInfo, form.getName(), form, form.getProject(), getAuditInfo(form.getNotebookName()))
-                ? Response.ok().build()
-                : Response.status(Response.Status.FOUND).build();
-    }
-
-	/**
-	 * Sends request to provisioning service for termination the computational resource for user.
-	 *
-	 * @param userInfo          user info.
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @return 200 OK if operation is successfully triggered
-	 */
-	@DELETE
-	@Path("/{projectName}/{exploratoryName}/{computationalName}/terminate")
-	public Response terminate(@Auth UserInfo userInfo,
-							  @PathParam("projectName") String projectName,
-							  @PathParam("exploratoryName") String exploratoryName,
-							  @PathParam("computationalName") String computationalName) {
-        log.debug("Terminating computational resource {} for user {}", computationalName, userInfo.getName());
-
-        computationalService.terminateComputational(userInfo, userInfo.getName(), projectName, exploratoryName, computationalName, getAuditInfo(exploratoryName));
-
-        return Response.ok().build();
-    }
-
-	/**
-	 * Sends request to provisioning service for stopping the computational resource for user.
-	 *
-	 * @param userInfo          user info.
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @return 200 OK if operation is successfully triggered
-	 */
-	@DELETE
-	@Path("/{project}/{exploratoryName}/{computationalName}/stop")
-	public Response stop(@Auth UserInfo userInfo,
-						 @PathParam("project") String project,
-						 @PathParam("exploratoryName") String exploratoryName,
-						 @PathParam("computationalName") String computationalName) {
-        log.debug("Stopping computational resource {} for user {}", computationalName, userInfo.getName());
-
-        computationalService.stopSparkCluster(userInfo, userInfo.getName(), project, exploratoryName, computationalName, getAuditInfo(exploratoryName));
-        return Response.ok().build();
-    }
-
-	/**
-	 * Sends request to provisioning service for starting the computational resource for user.
-	 *
-	 * @param userInfo          user info.
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @return 200 OK if operation is successfully triggered
-	 */
-	@PUT
-	@Path("/{project}/{exploratoryName}/{computationalName}/start")
-	public Response start(@Auth UserInfo userInfo,
-						  @PathParam("exploratoryName") String exploratoryName,
-						  @PathParam("computationalName") String computationalName,
-						  @PathParam("project") String project) {
-        log.debug("Starting computational resource {} for user {}", computationalName, userInfo.getName());
-
-        computationalService.startSparkCluster(userInfo, exploratoryName, computationalName, project, getAuditInfo(exploratoryName));
-        return Response.ok().build();
-    }
-
-	@PUT
-	@Path("dataengine/{projectName}/{exploratoryName}/{computationalName}/config")
-	public Response updateDataEngineConfig(@Auth UserInfo userInfo,
-										   @PathParam("projectName") String projectName,
-										   @PathParam("exploratoryName") String exploratoryName,
-										   @PathParam("computationalName") String computationalName,
-										   @Valid @NotNull List<ClusterConfig> config) {
-		computationalService.updateSparkClusterConfig(userInfo, projectName, exploratoryName, computationalName, config,
-				String.format(AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE, computationalName, exploratoryName));
-		return Response.ok().build();
-	}
-
-	@GET
-	@Path("/{projectName}/{exploratoryName}/{computationalName}/config")
-	public Response getClusterConfig(@Auth UserInfo userInfo,
-									 @PathParam("projectName") String projectName,
-									 @PathParam("exploratoryName") String exploratoryName,
-									 @PathParam("computationalName") String computationalName) {
-		return Response.ok(computationalService.getClusterConfig(userInfo, projectName, exploratoryName, computationalName)).build();
-	}
-
-	private void validate(SparkStandaloneClusterCreateForm form) {
-
-		int instanceCount = Integer.parseInt(form.getDataEngineInstanceCount());
-
-		if (instanceCount < configuration.getMinSparkInstanceCount()
-				|| instanceCount > configuration.getMaxSparkInstanceCount()) {
-			throw new IllegalArgumentException(String.format("Instance count should be in range [%d..%d]",
-					configuration.getMinSparkInstanceCount(), configuration.getMaxSparkInstanceCount()));
-		}
-
-		if (DataEngineType.fromDockerImageName(form.getImage()) != SPARK_STANDALONE) {
-			throw new IllegalArgumentException(String.format("Unknown data engine %s", form.getImage()));
-		}
-	}
-
-	private void validate(UserInfo userInfo, AwsComputationalCreateForm formDTO) {
-		if (!UserRoles.checkAccess(userInfo, RoleType.COMPUTATIONAL, formDTO.getImage(), userInfo.getRoles())) {
-			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());
-		}
-
-		int slaveInstanceCount = Integer.parseInt(formDTO.getInstanceCount());
-		if (slaveInstanceCount < configuration.getMinEmrInstanceCount() || slaveInstanceCount >
-				configuration.getMaxEmrInstanceCount()) {
-			log.debug("Creating computational resource {} for user {} fail: Limit exceeded to creation slave " +
-							"instances. Minimum is {}, maximum is {}",
-					formDTO.getName(), userInfo.getName(), configuration.getMinEmrInstanceCount(),
-					configuration.getMaxEmrInstanceCount());
-			throw new DlabException("Limit exceeded to creation slave instances. Minimum is " +
-					configuration.getMinEmrInstanceCount() + ", maximum is " + configuration.getMaxEmrInstanceCount() +
-					".");
-		}
-
-		if (formDTO.getSlaveInstanceSpotPctPrice() != null) {
-			int slaveSpotInstanceBidPct = formDTO.getSlaveInstanceSpotPctPrice();
-			if (formDTO.getSlaveInstanceSpot() && (slaveSpotInstanceBidPct < configuration.getMinEmrSpotInstanceBidPct()
-					|| slaveSpotInstanceBidPct > configuration.getMaxEmrSpotInstanceBidPct())) {
-				log.debug("Creating computational resource {} for user {} fail: Spot instances bidding percentage " +
-                                "value " +
-                                "out of the boundaries. Minimum is {}, maximum is {}",
-                        formDTO.getName(), userInfo.getName(), configuration.getMinEmrSpotInstanceBidPct(),
-                        configuration.getMaxEmrSpotInstanceBidPct());
-                throw new DlabException("Spot instances bidding percentage value out of the boundaries. Minimum is " +
-                        configuration.getMinEmrSpotInstanceBidPct() + ", maximum is " +
-                        configuration.getMaxEmrSpotInstanceBidPct() + ".");
-            }
-        }
-    }
-
-    private String getAuditInfo(String exploratoryName) {
-        return String.format(AUDIT_MESSAGE, exploratoryName);
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/AzureOauthResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/AzureOauthResource.java
deleted file mode 100644
index 8c999a9..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/AzureOauthResource.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.resources.azure;
-
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.azure.auth.AuthorizationCodeFlowResponse;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.auth.contract.SecurityAPI;
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.net.URI;
-
-@Path("/user/azure")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class AzureOauthResource {
-
-	@Inject
-	@Named(ServiceConsts.SECURITY_SERVICE_NAME)
-	private RESTService securityService;
-
-
-	@GET
-	@Path("/init")
-	public Response redirectedUrl() {
-		return Response.seeOther(URI.create(securityService.get(SecurityAPI.INIT_LOGIN_OAUTH_AZURE, String.class)))
-				.build();
-	}
-
-	@POST
-	@Path("/oauth")
-	public Response login(AuthorizationCodeFlowResponse codeFlowResponse) {
-		return securityService.post(SecurityAPI.LOGIN_OAUTH_AZURE, codeFlowResponse, Response.class);
-	}
-
-}
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
deleted file mode 100644
index 2240028..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * 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.resources.azure;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
-import com.epam.dlab.backendapi.roles.RoleType;
-import com.epam.dlab.backendapi.roles.UserRoles;
-import com.epam.dlab.backendapi.service.ComputationalService;
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.exceptions.DlabException;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import io.swagger.v3.oas.annotations.Parameter;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-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.List;
-
-import static com.epam.dlab.rest.contracts.ComputationalAPI.AUDIT_MESSAGE;
-import static com.epam.dlab.rest.contracts.ComputationalAPI.AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE;
-/**
- * Provides the REST API for the computational resource on Azure.
- */
-@Path("/azure/infrastructure_provision/computational_resources")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ComputationalResourceAzure {
-	private final ComputationalService computationalService;
-
-	@Inject
-	public ComputationalResourceAzure(ComputationalService computationalService) {
-		this.computationalService = computationalService;
-	}
-
-	@GET
-	@Path("/{project}/{endpoint}/templates")
-	public Response getTemplates(@Auth @Parameter(hidden = true) UserInfo userInfo, @PathParam("project") String project,
-								 @PathParam("endpoint") String endpoint) {
-		return Response.ok(computationalService.getComputationalNamesAndTemplates(userInfo, project, endpoint)).build();
-	}
-
-	/**
-	 * Asynchronously creates computational Spark cluster.
-	 *
-	 * @param userInfo user info.
-	 * @param form     user info about creation of the computational resource.
-	 * @return 200 OK if request success, 302 Found - for duplicates, otherwise throws exception.
-	 * @throws IllegalArgumentException if input is not valid or exceeds configuration limits
-	 */
-	@PUT
-	@Path("dataengine")
-	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.getName(), form, form.getProject(), getAuditInfo(form.getNotebookName()))
-                ? Response.ok().build()
-                : Response.status(Response.Status.FOUND).build();
-    }
-
-	/**
-	 * Sends request to provisioning service for termination the computational resource for user.
-	 *
-	 * @param userInfo          user info.
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @return 200 OK if operation is successfully triggered
-	 */
-	@DELETE
-	@Path("/{projectName}/{exploratoryName}/{computationalName}/terminate")
-	public Response terminate(@Auth UserInfo userInfo,
-							  @PathParam("projectName") String projectName,
-							  @PathParam("exploratoryName") String exploratoryName,
-							  @PathParam("computationalName") String computationalName) {
-
-        log.debug("Terminating computational resource {} for user {}", computationalName, userInfo.getName());
-
-        computationalService.terminateComputational(userInfo, userInfo.getName(), projectName, exploratoryName, computationalName, getAuditInfo(exploratoryName));
-        return Response.ok().build();
-    }
-
-	/**
-	 * Sends request to provisioning service for stopping the computational resource for user.
-	 *
-	 * @param userInfo          user info.
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @return 200 OK if operation is successfully triggered
-	 */
-	@DELETE
-	@Path("/{project}/{exploratoryName}/{computationalName}/stop")
-	public Response stop(@Auth UserInfo userInfo,
-						 @PathParam("project") String project,
-						 @PathParam("exploratoryName") String exploratoryName,
-						 @PathParam("computationalName") String computationalName) {
-        log.debug("Stopping computational resource {} for user {}", computationalName, userInfo.getName());
-
-        computationalService.stopSparkCluster(userInfo, userInfo.getName(), project, exploratoryName, computationalName, getAuditInfo(exploratoryName));
-        return Response.ok().build();
-    }
-
-	/**
-	 * Sends request to provisioning service for starting the computational resource for user.
-	 *
-	 * @param userInfo          user info.
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @return 200 OK if operation is successfully triggered
-	 */
-	@PUT
-	@Path("/{project}/{exploratoryName}/{computationalName}/start")
-	public Response start(@Auth UserInfo userInfo,
-						  @PathParam("exploratoryName") String exploratoryName,
-						  @PathParam("computationalName") String computationalName,
-						  @PathParam("project") String project) {
-        log.debug("Starting computational resource {} for user {}", computationalName, userInfo.getName());
-
-        computationalService.startSparkCluster(userInfo, exploratoryName, computationalName, project, getAuditInfo(exploratoryName));
-        return Response.ok().build();
-    }
-
-	@PUT
-	@Path("dataengine/{projectName}/{exploratoryName}/{computationalName}/config")
-	public Response updateDataEngineConfig(@Auth UserInfo userInfo,
-										   @PathParam("projectName") String projectName,
-										   @PathParam("exploratoryName") String exploratoryName,
-										   @PathParam("computationalName") String computationalName,
-										   @Valid @NotNull List<ClusterConfig> config) {
-
-		computationalService.updateSparkClusterConfig(userInfo, projectName, exploratoryName, computationalName, config,
-				String.format(AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE, computationalName, exploratoryName));
-		return Response.ok().build();
-    }
-
-    @GET
-    @Path("/{projectName}/{exploratoryName}/{computationalName}/config")
-    public Response getClusterConfig(@Auth UserInfo userInfo,
-                                     @PathParam("projectName") String projectName,
-                                     @PathParam("exploratoryName") String exploratoryName,
-                                     @PathParam("computationalName") String computationalName) {
-        return Response.ok(computationalService.getClusterConfig(userInfo, projectName, exploratoryName, computationalName)).build();
-    }
-
-    private String getAuditInfo(String exploratoryName) {
-        return String.format(AUDIT_MESSAGE, exploratoryName);
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/BackupCallback.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/BackupCallback.java
deleted file mode 100644
index 102f8bf..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/BackupCallback.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.resources.callback;
-
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.BackupService;
-import com.epam.dlab.dto.backup.EnvBackupStatusDTO;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-@Path("infrastructure/backup")
-@Consumes(MediaType.APPLICATION_JSON)
-@Slf4j
-public class BackupCallback {
-
-	@Inject
-	private BackupService backupService;
-
-	@Inject
-	private RequestId requestId;
-
-	@Context
-	private UriInfo uriInfo;
-
-	@POST
-	@Path("/status")
-	public Response status(EnvBackupStatusDTO dto) {
-		requestId.remove(dto.getRequestId());
-		log.debug("Updating status of backup status to {}", dto);
-		backupService.updateStatus(dto.getEnvBackupDTO(), dto.getUser(),
-				dto.getEnvBackupStatus().withErrorMessage(dto.getErrorMessage()));
-		return Response.created(uriInfo.getRequestUri()).build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/CheckInactivityCallback.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/CheckInactivityCallback.java
deleted file mode 100644
index abf4c6d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/CheckInactivityCallback.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.resources.callback;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.InactivityService;
-import com.epam.dlab.dto.computational.CheckInactivityStatusDTO;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-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;
-import java.time.LocalDateTime;
-
-import static java.time.Instant.ofEpochSecond;
-import static java.time.ZoneId.systemDefault;
-
-@Path("/infrastructure/inactivity/callback")
-@Consumes(MediaType.APPLICATION_JSON)
-@Slf4j
-public class CheckInactivityCallback {
-
-	@Inject
-	private RequestId requestId;
-	@Inject
-	private InactivityService inactivityService;
-
-	@POST
-	@Path("exploratory")
-	public Response updateExploratoryLastActivity(CheckInactivityStatusDTO dto) {
-		requestId.checkAndRemove(dto.getRequestId());
-		inactivityService.updateLastActivityForExploratory(new UserInfo(dto.getUser(), null), dto.getExploratoryName(),
-				toLocalDateTime(dto.getLastActivityUnixTime()));
-		return Response.ok().build();
-	}
-
-	@POST
-	@Path("computational")
-	public Response updateComputationalLastActivity(CheckInactivityStatusDTO dto) {
-		requestId.checkAndRemove(dto.getRequestId());
-		inactivityService.updateLastActivityForComputational(new UserInfo(dto.getUser(), null), null,
-				dto.getExploratoryName(), dto.getComputationalName(), toLocalDateTime(dto.getLastActivityUnixTime()));
-		return Response.ok().build();
-	}
-
-	private LocalDateTime toLocalDateTime(long unixTime) {
-		return ofEpochSecond(unixTime).atZone(systemDefault()).toLocalDateTime();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ComputationalCallback.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ComputationalCallback.java
deleted file mode 100644
index 2b286b5..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ComputationalCallback.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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.resources.callback;
-
-import com.epam.dlab.backendapi.dao.ComputationalDAO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.ComputationalService;
-import com.epam.dlab.backendapi.service.ReuploadKeyService;
-import com.epam.dlab.backendapi.service.SecurityService;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.computational.ComputationalStatusDTO;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-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;
-import java.util.Date;
-
-@Path("/infrastructure_provision/computational_resources")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ComputationalCallback {
-
-	@Inject
-	private ComputationalDAO computationalDAO;
-	@Inject
-	private RequestId requestId;
-	@Inject
-	private SecurityService securityService;
-	@Inject
-	private ReuploadKeyService reuploadKeyService;
-	@Inject
-	private ComputationalService computationalService;
-
-	/**
-	 * Updates the status of the computational resource for user.
-	 *
-	 * @param dto DTO info about the status of the computational resource.
-	 * @return 200 OK - if request success otherwise throws exception.
-	 */
-	@POST
-	@Path(ApiCallbacks.STATUS_URI)
-	public Response status(ComputationalStatusDTO dto) {
-		log.debug("Updating status for computational resource {} for user {}: {}",
-				dto.getComputationalName(), dto.getUser(), dto);
-		String uuid = dto.getRequestId();
-		requestId.checkAndRemove(uuid);
-
-		UserComputationalResource compResource = computationalService.getComputationalResource(dto.getUser(), dto.getProject(),
-				dto.getExploratoryName(), dto.getComputationalName())
-				.orElseThrow(() ->
-						new DlabException(String.format("Computational resource %s of exploratory environment %s of " +
-										"project %s for user %s doesn't exist", dto.getComputationalName(),
-								dto.getExploratoryName(), dto.getProject(), dto.getUser())));
-		log.debug("Current status for computational resource {} of exploratory environment {} for user {} is {}",
-				dto.getComputationalName(), dto.getExploratoryName(), dto.getUser(),
-				compResource.getStatus());
-		try {
-			computationalDAO.updateComputationalFields(dto.withLastActivity(new Date()));
-		} catch (DlabException e) {
-			log.error("Could not update status for computational resource {} for user {} to {}: {}", dto, e);
-			throw e;
-		}
-		if (UserInstanceStatus.CONFIGURING == UserInstanceStatus.of(dto.getStatus())) {
-			log.debug("Waiting for configuration of the computational resource {} for user {}",
-					dto.getComputationalName(), dto.getUser());
-			requestId.put(dto.getUser(), uuid);
-		}
-		return Response.ok().build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/EnvironmentStatusCallback.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/EnvironmentStatusCallback.java
deleted file mode 100644
index d4c059e..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/EnvironmentStatusCallback.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.resources.callback;
-
-import com.epam.dlab.backendapi.dao.EnvDAO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.status.EnvStatusDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-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;
-
-@Path("/infrastructure")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class EnvironmentStatusCallback {
-
-    @Inject
-	private EnvDAO envDAO;
-	@Inject
-	private RequestId requestId;
-
-    /**
-     * Updates the status of the resources for user.
-     *
-     * @param dto DTO info about the statuses of resources.
-     * @return Always return code 200 (OK).
-     */
-    @POST
-    @Path(ApiCallbacks.STATUS_URI)
-    public Response status(EnvStatusDTO dto) {
-        log.trace("Updating the status of resources for user {}: {}", dto.getUser(), dto);
-		requestId.checkAndRemove(dto.getRequestId());
-        try {
-            if (UserInstanceStatus.FAILED == UserInstanceStatus.of(dto.getStatus())) {
-                log.warn("Request for the status of resources for user {} fails: {}", dto.getUser(), dto.getErrorMessage());
-            } else {
-                envDAO.updateEnvStatus(dto.getUser(), null, dto.getResourceList());
-            }
-        } catch (DlabException e) {
-            log.warn("Could not update status of resources for user {}: {}", dto.getUser(), e.getLocalizedMessage(), e);
-        }
-        return Response.ok().build();
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ExploratoryCallback.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ExploratoryCallback.java
deleted file mode 100644
index c275a18..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ExploratoryCallback.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * 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.resources.callback;
-
-import com.epam.dlab.backendapi.dao.ComputationalDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.ExploratoryService;
-import com.epam.dlab.backendapi.service.ReuploadKeyService;
-import com.epam.dlab.backendapi.service.SecurityService;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.exploratory.ExploratoryStatusDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-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;
-import java.util.Date;
-
-import static com.epam.dlab.dto.UserInstanceStatus.FAILED;
-import static com.epam.dlab.dto.UserInstanceStatus.STOPPED;
-import static com.epam.dlab.dto.UserInstanceStatus.STOPPING;
-import static com.epam.dlab.dto.UserInstanceStatus.TERMINATED;
-import static com.epam.dlab.dto.UserInstanceStatus.TERMINATING;
-
-
-@Path("/infrastructure_provision/exploratory_environment")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ExploratoryCallback {
-
-	private static final String USER_INSTANCE_NOT_EXIST_MSG = "User instance with exploratory name %s for user %s " +
-			"doesn't exist";
-	@Inject
-	private ExploratoryDAO exploratoryDAO;
-	@Inject
-	private ComputationalDAO computationalDAO;
-	@Inject
-	private RequestId requestId;
-	@Inject
-	private SecurityService securityService;
-	@Inject
-	private ReuploadKeyService reuploadKeyService;
-	@Inject
-	private ExploratoryService exploratoryService;
-
-	/**
-	 * Changes the status of exploratory environment.
-	 *
-	 * @param dto description of status.
-	 * @return 200 OK - if request success.
-	 */
-	@POST
-	@Path(ApiCallbacks.STATUS_URI)
-	public Response status(ExploratoryStatusDTO dto) {
-		log.debug("Updating status for exploratory environment {} for user {} to {}",
-				dto.getExploratoryName(), dto.getUser(), dto.getStatus());
-		requestId.checkAndRemove(dto.getRequestId());
-
-		UserInstanceDTO instance = exploratoryService.getUserInstance(dto.getUser(), dto.getProject(), dto.getExploratoryName())
-				.orElseThrow(() -> new DlabException(String.format(USER_INSTANCE_NOT_EXIST_MSG,
-						dto.getExploratoryName(), dto.getUser())));
-
-		UserInstanceStatus currentStatus = UserInstanceStatus.of(instance.getStatus());
-		log.debug("Current status for exploratory environment {} for user {} is {}",
-				dto.getExploratoryName(), dto.getUser(), currentStatus);
-
-		try {
-			exploratoryDAO.updateExploratoryFields(dto.withLastActivity(new Date()));
-			if (currentStatus == TERMINATING) {
-				updateComputationalStatuses(dto.getUser(), dto.getProject(), dto.getExploratoryName(),
-						UserInstanceStatus.of(dto.getStatus()));
-			} else if (currentStatus == STOPPING) {
-				updateComputationalStatuses(dto.getUser(), dto.getProject(), dto.getExploratoryName(),
-						UserInstanceStatus.of(dto.getStatus()), TERMINATED, FAILED, TERMINATED, STOPPED);
-			}
-		} catch (DlabException e) {
-			log.error("Could not update status for exploratory environment {} in project {} for user {} to {}",
-					dto.getExploratoryName(), dto.getProject(), dto.getUser(), dto.getStatus(), e);
-			throw new DlabException("Could not update status for exploratory environment " + dto.getExploratoryName() +
-					" for user " + dto.getUser() + " to " + dto.getStatus() + ": " + e.getLocalizedMessage(), e);
-		}
-
-		return Response.ok().build();
-	}
-
-	/**
-	 * Updates the computational status of exploratory environment.
-	 *
-	 * @param user            user name
-	 * @param project         project name
-	 * @param exploratoryName name of exploratory environment.
-	 * @param status          status for exploratory environment.
-	 */
-	private void updateComputationalStatuses(String user, String project, String exploratoryName, UserInstanceStatus status) {
-		log.debug("updating status for all computational resources of {} for user {}: {}", exploratoryName, user,
-				status);
-		computationalDAO.updateComputationalStatusesForExploratory(new ExploratoryStatusDTO()
-				.withUser(user)
-				.withExploratoryName(exploratoryName)
-				.withProject(project)
-				.withStatus(status));
-	}
-
-	private void updateComputationalStatuses(String user, String project, String exploratoryName, UserInstanceStatus
-			dataEngineStatus, UserInstanceStatus dataEngineServiceStatus, UserInstanceStatus... excludedStatuses) {
-		log.debug("updating status for all computational resources of {} for user {}: DataEngine {}, " +
-				"dataengine-service {}", exploratoryName, user, dataEngineStatus, dataEngineServiceStatus);
-		computationalDAO.updateComputationalStatusesForExploratory(user, project, exploratoryName,
-				dataEngineStatus, dataEngineServiceStatus, excludedStatuses);
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/GitCredsCallback.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/GitCredsCallback.java
deleted file mode 100644
index 3ef98c2..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/GitCredsCallback.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.resources.callback;
-
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.exploratory.ExploratoryStatusDTO;
-import com.epam.dlab.rest.contracts.ApiCallbacks;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-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;
-
-@Path("/user/git_creds")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class GitCredsCallback {
-
-	@Inject
-	private RequestId requestId;
-
-    /**
-     * Update GIT credentials status in Mongo DB for user.
-     *
-     * @param dto description of status.
-     * @return 200 OK - if request success.
-     */
-    @POST
-    @Path(ApiCallbacks.STATUS_URI)
-    public Response status(ExploratoryStatusDTO dto) {
-        if (UserInstanceStatus.CREATED != UserInstanceStatus.of(dto.getStatus())) {
-            log.error("Git creds has not been updated for exploratory environment {} for user {}, status is {}",
-                    dto.getExploratoryName(), dto.getUser(), dto.getStatus());
-        } else {
-            log.debug("Git creds has been updated for exploratory environment {} for user {}, status is {}",
-                    dto.getExploratoryName(), dto.getUser(), dto.getStatus());
-        }
-		requestId.checkAndRemove(dto.getRequestId());
-        return Response.ok().build();
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ImageCallback.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ImageCallback.java
deleted file mode 100644
index 66b54b6..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ImageCallback.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.resources.callback;
-
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.ImageExploratoryService;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.exploratory.ImageCreateStatusDTO;
-import com.epam.dlab.dto.exploratory.ImageStatus;
-import com.epam.dlab.model.exploratory.Image;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-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;
-
-@Path("/infrastructure_provision/image")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ImageCallback {
-
-	@Inject
-	private ImageExploratoryService imageExploratoryService;
-	@Inject
-	private RequestId requestId;
-
-	@POST
-	@Path("/image_status")
-	public Response imageCreateStatus(ImageCreateStatusDTO dto) {
-		log.debug("Updating status of image {} for user {} to {}", dto.getName(), dto.getUser(), dto);
-		requestId.remove(dto.getRequestId());
-		imageExploratoryService.finishImageCreate(getImage(dto), dto.getExploratoryName(), dto.getImageCreateDTO()
-				.getIp());
-		return Response.status(Response.Status.CREATED).build();
-	}
-
-	private Image getImage(ImageCreateStatusDTO dto) {
-		return Image.builder()
-				.name(dto.getName())
-				.user(dto.getUser())
-				.project(dto.getProject())
-				.endpoint(dto.getEndpoint())
-				.externalName(dto.getImageCreateDTO().getExternalName())
-				.fullName(dto.getImageCreateDTO().getFullName())
-				.status(UserInstanceStatus.FAILED == UserInstanceStatus.of(dto.getStatus()) ?
-						ImageStatus.FAILED : dto.getImageCreateDTO().getStatus())
-				.application(dto.getImageCreateDTO().getApplication()).build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/LibraryCallback.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/LibraryCallback.java
deleted file mode 100644
index 63af14b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/LibraryCallback.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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.resources.callback;
-
-import com.epam.dlab.backendapi.dao.ExploratoryLibDAO;
-import com.epam.dlab.backendapi.domain.ExploratoryLibCache;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.exploratory.LibInstallStatusDTO;
-import com.epam.dlab.dto.exploratory.LibListStatusDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-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;
-
-@Path("/infrastructure_provision/library")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class LibraryCallback {
-
-	@Inject
-	private ExploratoryLibDAO libraryDAO;
-	@Inject
-	private RequestId requestId;
-
-	/**
-	 * Changes the status of installed libraries for exploratory environment.
-	 *
-	 * @param dto description of status.
-	 * @return 200 OK - if request success.
-	 */
-	@POST
-	@Path("/lib_status")
-	public Response libInstallStatus(LibInstallStatusDTO dto) {
-		log.debug("Updating status of libraries for exploratory environment {} for user {} to {}",
-				dto.getExploratoryName(), dto.getUser(), dto);
-		requestId.checkAndRemove(dto.getRequestId());
-		try {
-			libraryDAO.updateLibraryFields(dto);
-		} catch (DlabException e) {
-			log.error("Cannot update status of libraries for exploratory environment {} for user {} to {}",
-					dto.getExploratoryName(), dto.getUser(), dto, e);
-			throw new DlabException("Cannot update status of libaries for exploratory environment " + dto.getExploratoryName() +
-					" for user " + dto.getUser() + ": " + e.getLocalizedMessage(), e);
-		}
-
-		return Response.ok().build();
-	}
-
-
-	/**
-	 * Updates the list of libraries.
-	 *
-	 * @param dto DTO the list of libraries.
-	 * @return Always return code 200 (OK).
-	 */
-	@POST
-	@Path("/update_lib_list")
-	public Response updateLibList(LibListStatusDTO dto) {
-		log.debug("Updating the list of libraries for image {}", dto.getGroup());
-		requestId.checkAndRemove(dto.getRequestId());
-		try {
-			if (UserInstanceStatus.FAILED == UserInstanceStatus.of(dto.getStatus())) {
-				log.warn("Request for the list of libraries for {} fails: {}", dto.getGroup(), dto.getErrorMessage());
-				ExploratoryLibCache.getCache().updateLibListStatus(dto.getGroup());
-			} else {
-				ExploratoryLibCache.getCache().updateLibList(dto.getGroup(), dto.getLibs());
-			}
-		} catch (Exception e) {
-			log.warn("Cannot update the list of libs: {}", e.getLocalizedMessage(), e);
-		}
-		return Response.ok().build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ProjectCallback.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ProjectCallback.java
deleted file mode 100644
index 4500e5e..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ProjectCallback.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.resources.callback;
-
-import com.epam.dlab.backendapi.dao.ProjectDAO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.ExploratoryService;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.project.ProjectResult;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-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;
-import java.util.Objects;
-
-@Path("/project/status")
-@Consumes(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ProjectCallback {
-
-	private final ProjectDAO projectDAO;
-	private final ExploratoryService exploratoryService;
-	private final RequestId requestId;
-
-	@Inject
-	public ProjectCallback(ProjectDAO projectDAO, ExploratoryService exploratoryService, RequestId requestId) {
-		this.projectDAO = projectDAO;
-		this.exploratoryService = exploratoryService;
-		this.requestId = requestId;
-	}
-
-
-	@POST
-	public Response updateProjectStatus(ProjectResult projectResult) {
-		requestId.checkAndRemove(projectResult.getRequestId());
-		final String projectName = projectResult.getProjectName();
-		final UserInstanceStatus status = UserInstanceStatus.of(projectResult.getStatus());
-		if (UserInstanceStatus.RUNNING == status && Objects.nonNull(projectResult.getEdgeInfo())) {
-			projectDAO.updateEdgeInfo(projectName, projectResult.getEndpointName(), projectResult.getEdgeInfo());
-		} else {
-			updateExploratoriesStatusIfNeeded(status, projectResult.getProjectName(), projectResult.getEndpointName());
-			projectDAO.updateEdgeStatus(projectName, projectResult.getEndpointName(), status);
-		}
-		return Response.ok().build();
-	}
-
-	private void updateExploratoriesStatusIfNeeded(UserInstanceStatus status, String projectName, String endpoint) {
-		if (UserInstanceStatus.TERMINATED == status) {
-			exploratoryService.updateProjectExploratoryStatuses(projectName, endpoint, UserInstanceStatus.TERMINATED);
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ReuploadKeyCallback.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ReuploadKeyCallback.java
deleted file mode 100644
index 51324a4..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ReuploadKeyCallback.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.resources.callback;
-
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.ReuploadKeyService;
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyStatusDTO;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-@Path("infrastructure/reupload_key")
-@Consumes(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ReuploadKeyCallback {
-
-	@Inject
-	private RequestId requestId;
-	@Inject
-	private ReuploadKeyService reuploadKeyService;
-
-	@Context
-	private UriInfo uriInfo;
-
-	@POST
-	@Path("/callback")
-	public Response reuploadKeyResponse(ReuploadKeyStatusDTO dto) {
-		requestId.remove(dto.getRequestId());
-		reuploadKeyService.updateResourceData(dto);
-		return Response.ok(uriInfo.getRequestUri()).build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BackupFormDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BackupFormDTO.java
deleted file mode 100644
index 36f08e9..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BackupFormDTO.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.resources.dto;
-
-import lombok.Data;
-import lombok.ToString;
-import org.hibernate.validator.constraints.NotEmpty;
-
-import java.util.List;
-
-@Data
-@ToString
-public class BackupFormDTO {
-	@NotEmpty
-	private final List<String> configFiles;
-	@NotEmpty
-	private final List<String> keys;
-	@NotEmpty
-	private final List<String> certificates;
-	private final List<String> jars;
-	private final boolean databaseBackup;
-	private final boolean logsBackup;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BackupInfoRecord.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BackupInfoRecord.java
deleted file mode 100644
index 3a3dfa8..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BackupInfoRecord.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.dto.backup.EnvBackupStatus;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.util.Date;
-import java.util.List;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class BackupInfoRecord {
-
-	private final List<String> configFiles;
-	private final List<String> keys;
-	private final List<String> certificates;
-	private final List<String> jars;
-	private final boolean databaseBackup;
-	private final boolean logsBackup;
-	private final String backupFile;
-	private final EnvBackupStatus status;
-	@JsonProperty("error_message")
-	private final String errorMessage;
-	private final Date timestamp;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BillingFilter.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BillingFilter.java
deleted file mode 100644
index 52363a8..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BillingFilter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.NonNull;
-
-import java.util.Collections;
-import java.util.List;
-
-@Data
-@NoArgsConstructor
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class BillingFilter {
-	@NonNull
-	private List<String> users;
-	@NonNull
-	@JsonProperty("dlab_id")
-	private String dlabId;
-	@NonNull
-	@JsonProperty("date_start")
-	private String dateStart;
-	@NonNull
-	@JsonProperty("date_end")
-	private String dateEnd;
-	@NonNull
-	@JsonProperty("resource_type")
-	private List<String> resourceTypes;
-	@NonNull
-	private List<UserInstanceStatus> statuses = Collections.emptyList();
-	@NonNull
-	private List<String> projects;
-	@NonNull
-	private List<String> products;
-	@NonNull
-	private List<String> shapes;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BucketDeleteDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BucketDeleteDTO.java
deleted file mode 100644
index 9f12a86..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BucketDeleteDTO.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.Data;
-import org.hibernate.validator.constraints.NotBlank;
-import org.hibernate.validator.constraints.NotEmpty;
-
-import java.util.List;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class BucketDeleteDTO {
-    @NotBlank(message = "field cannot be empty")
-    private final String bucket;
-    @NotBlank(message = "field cannot be empty")
-    private final String endpoint;
-    @NotEmpty(message = "field cannot be empty")
-    private final List<String> objects;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BucketDownloadDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BucketDownloadDTO.java
deleted file mode 100644
index eb26202..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/BucketDownloadDTO.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.Data;
-import org.hibernate.validator.constraints.NotBlank;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class BucketDownloadDTO {
-    @NotBlank(message = "field cannot be empty")
-    private final String bucket;
-    @NotBlank(message = "field cannot be empty")
-    private final String object;
-    @NotBlank(message = "field cannot be empty")
-    private final String endpoint;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ComputationalCreateFormDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ComputationalCreateFormDTO.java
deleted file mode 100644
index ce619e4..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ComputationalCreateFormDTO.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import org.hibernate.validator.constraints.NotBlank;
-
-import javax.validation.Valid;
-import java.util.List;
-
-/**
- * Stores info about creation of the computational resource.
- */
-@Data
-public class ComputationalCreateFormDTO {
-
-	@NotBlank
-	@JsonProperty("template_name")
-	private String templateName;
-
-	@NotBlank
-	@JsonProperty
-	private String image;
-
-	@NotBlank
-	@JsonProperty
-	private String name;
-
-	@NotBlank
-	@JsonProperty
-	private String project;
-	@JsonProperty("custom_tag")
-	private String customTag;
-
-	@NotBlank
-	@JsonProperty("notebook_name")
-	private String notebookName;
-
-	@JsonProperty("check_inactivity_required")
-	private boolean checkInactivityRequired = true;
-
-	@Valid
-	private List<ClusterConfig> config;
-
-}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ComputationalTemplatesDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ComputationalTemplatesDTO.java
deleted file mode 100644
index 9871918..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ComputationalTemplatesDTO.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.dto.base.computational.FullComputationalTemplate;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class ComputationalTemplatesDTO {
-    private final List<FullComputationalTemplate> templates;
-    @JsonProperty("user_computations")
-    private final List<String> userComputations;
-    @JsonProperty("project_computations")
-    private final List<String> projectComputations;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryActionFormDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryActionFormDTO.java
deleted file mode 100644
index d3361df..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryActionFormDTO.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import org.hibernate.validator.constraints.NotBlank;
-
-/**
- * Stores info about action on the exploratory resource.
- */
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class ExploratoryActionFormDTO {
-    @NotBlank
-    @JsonProperty("notebook_instance_name")
-    private String notebookInstanceName;
-
-    @NotBlank
-    @JsonProperty("project_name")
-    private String projectName;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryCreateFormDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryCreateFormDTO.java
deleted file mode 100644
index e157b8b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryCreateFormDTO.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-import org.hibernate.validator.constraints.NotBlank;
-
-import java.util.List;
-
-/**
- * Stores info about new exploratory.
- */
-public class ExploratoryCreateFormDTO {
-	@NotBlank
-	@JsonProperty
-	private String image;
-
-	@NotBlank
-	@JsonProperty("template_name")
-	private String templateName;
-
-	@NotBlank
-	@JsonProperty
-	private String name;
-
-	@NotBlank
-	@JsonProperty
-	private String project;
-	@JsonProperty("custom_tag")
-	private String exploratoryTag;
-
-	@NotBlank
-	@JsonProperty
-	private String endpoint;
-
-	@NotBlank
-	@JsonProperty
-	private String shape;
-
-	@NotBlank
-	@JsonProperty
-	private String version;
-
-	@JsonProperty("notebook_image_name")
-	private String imageName;
-
-	@JsonProperty("cluster_config")
-	private List<ClusterConfig> clusterConfig;
-
-	/**
-	 * Returns the image name of notebook.
-	 */
-	public String getImage() {
-		return image;
-	}
-
-	/**
-	 * Sets the image name of notebook.
-	 */
-	public void setImage(String image) {
-		this.image = image;
-	}
-
-	/**
-	 * Returns name of template.
-	 */
-	public String getTemplateName() {
-		return templateName;
-	}
-
-	/**
-	 * Sets name of template.
-	 */
-	public void setTemplateName(String templateName) {
-		this.templateName = templateName;
-	}
-
-	/**
-	 * Returns name of notebook.
-	 */
-	public String getName() {
-		return name;
-	}
-
-	/**
-	 * Sets name of notebook.
-	 */
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	/**
-	 * Returns name of shape.
-	 */
-	public String getShape() {
-		return shape;
-	}
-
-	/**
-	 * Sets name of shape.
-	 */
-	public void setShape(String shape) {
-		this.shape = shape;
-	}
-
-	/**
-	 * Returns version.
-	 */
-	public String getVersion() {
-		return version;
-	}
-
-	/**
-	 * Sets version.
-	 */
-	public void setVersion(String version) {
-		this.version = version;
-	}
-
-	/**
-	 * Returns image name from which notebook should be created
-	 */
-	public String getImageName() {
-		return imageName;
-	}
-
-	/**
-	 * Sets image name from which notebook should be created
-	 */
-	public void setImageName(String imageName) {
-		this.imageName = imageName;
-	}
-
-	public List<ClusterConfig> getClusterConfig() {
-		return clusterConfig;
-	}
-
-	public String getProject() {
-		return project;
-	}
-
-	public void setProject(String project) {
-		this.project = project;
-	}
-
-	public String getEndpoint() {
-		return endpoint;
-	}
-
-	public void setEndpoint(String endpoint) {
-		this.endpoint = endpoint;
-	}
-
-	public String getExploratoryTag() {
-		return exploratoryTag;
-	}
-
-	@Override
-	public String toString() {
-		return MoreObjects.toStringHelper(this)
-				.add("name", name)
-				.add("templateName", templateName)
-				.add("shape", shape)
-				.add("version", version)
-				.add("image", image)
-				.add("imageName", imageName)
-				.toString();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryCreatePopUp.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryCreatePopUp.java
deleted file mode 100644
index d061204..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryCreatePopUp.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.util.List;
-import java.util.Map;
-
-@Data
-public class ExploratoryCreatePopUp {
-    @JsonProperty("user_projects")
-    private final List<ProjectDTO> userProjects;
-    @JsonProperty("project_exploratories")
-    private final Map<String, List<String>> projectExploratories;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryImageCreateFormDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryImageCreateFormDTO.java
deleted file mode 100644
index 14193f2..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryImageCreateFormDTO.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.ToString;
-import org.hibernate.validator.constraints.NotBlank;
-
-@Data
-@ToString
-public class ExploratoryImageCreateFormDTO {
-    @NotBlank
-    private final String name;
-    @NotBlank
-    @JsonProperty("exploratory_name")
-    private String notebookName;
-    @NotBlank
-    @JsonProperty("project_name")
-    private String projectName;
-    private final String description;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/FolderUploadDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/FolderUploadDTO.java
deleted file mode 100644
index 1539118..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/FolderUploadDTO.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.Data;
-import org.hibernate.validator.constraints.NotBlank;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class FolderUploadDTO {
-    @NotBlank(message = "field cannot be empty")
-    private final String bucket;
-    @NotBlank(message = "field cannot be empty")
-    private final String folder;
-    @NotBlank(message = "field cannot be empty")
-    private final String endpoint;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/GroupDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/GroupDTO.java
deleted file mode 100644
index ffce74b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/GroupDTO.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.resources.dto;
-
-import lombok.Getter;
-import lombok.Setter;
-import org.hibernate.validator.constraints.NotEmpty;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-@Getter
-@Setter
-public class GroupDTO {
-	@NotEmpty
-	private String name;
-	@NotEmpty
-	private Map<String,String> roleIds;
-	private Set<String> users = Collections.emptySet();
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusDTO.java
deleted file mode 100644
index 27c6b78..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusDTO.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-/** Stores the health statuses for services.
- */
-public class HealthStatusDTO {
-    @JsonProperty("mongo_alive")
-    private boolean mongoAlive;
-    @JsonProperty("provisioning_alive")
-    private boolean provisioningAlive;
-
-    /** Returns <b>true</b> if the Mongo database is available. */
-    public boolean isMongoAlive() {
-        return mongoAlive;
-    }
-
-    /** Sets the Mongo database availability. */
-    public void setMongoAlive(boolean mongoAlive) {
-        this.mongoAlive = mongoAlive;
-    }
-
-    /** Sets the Mongo database availability. */
-    public HealthStatusDTO withMongoAlive(boolean mongoAlive) {
-        setMongoAlive(mongoAlive);
-        return this;
-    }
-
-    /** Returns <b>true</b> if the provisioning service is available. */
-    public boolean isProvisioningAlive() {
-        return provisioningAlive;
-    }
-
-    /** Sets the provisioning service availability. */
-    public void setProvisioningAlive(boolean provisioningAlive) {
-        this.provisioningAlive = provisioningAlive;
-    }
-
-    /** Sets the provisioning service availability. */
-    public HealthStatusDTO withProvisioningAlive(boolean provisioningAlive) {
-        setProvisioningAlive(provisioningAlive);
-        return this;
-    }
-    
-    @Override
-    public String toString() {
-    	return MoreObjects.toStringHelper(this)
-    			.add("mongoAlive", mongoAlive)
-    			.add("provisioningAlive", provisioningAlive)
-    	        .toString();
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusEnum.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusEnum.java
deleted file mode 100644
index 3919532..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusEnum.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.resources.dto;
-
-/** Statuses for the environment resource. */
-public enum HealthStatusEnum {
-    ERROR,
-    WARNING,
-    OK;
-
-    @Override
-    public String toString() {
-        return super.toString().toLowerCase();
-    }
-
-    public static HealthStatusEnum of(String status) {
-        if (status != null) {
-            for (HealthStatusEnum uis : HealthStatusEnum.values()) {
-                if (status.equalsIgnoreCase(uis.toString())) {
-                    return uis;
-                }
-            }
-        }
-        return null;
-    }
-}
\ No newline at end of file
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
deleted file mode 100644
index 73fd421..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.resources.dto;
-
-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 auditEnabled;
-	@JsonProperty
-	private boolean admin;
-	@JsonProperty
-	private boolean projectAdmin;
-	@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
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusResource.java
deleted file mode 100644
index 039a31e..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusResource.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-/** Stores the health status for user environment.
- */
-public class HealthStatusResource {
-    @JsonProperty("type")
-    private String type;
-    @JsonProperty("resource_id")
-    private String resourceId;
-    @JsonProperty("status")
-    private String status;
-
-    /** Return the type of resource. */
-    public String getType() {
-        return type;
-    }
-
-    /** Set the type of resource. */
-    public void setType(String type) {
-        this.type = type;
-    }
-
-    /** Set the type of resource. */
-    public HealthStatusResource withType(String type) {
-        setType(type);
-        return this;
-    }
-
-    /** Return the id of resource (ip address, path, etc). */
-    public String getResourceId() {
-        return resourceId;
-    }
-
-    /** Set the id of resource (ip address, path, etc). */
-    public void setResourceId(String resourceId) {
-        this.resourceId = resourceId;
-    }
-
-    /** Set the id of resource (ip address, path, etc). */
-    public HealthStatusResource withResourceId(String resourceId) {
-        setResourceId(resourceId);
-        return this;
-    }
-
-    /** Return the status of resource. */
-    public String getStatus() {
-        return status;
-    }
-    
-    /** Set the status of resource. */
-    public void setStatus(String status) {
-        this.status = status;
-    }
-
-    /** Set the status of resource. */
-	public HealthStatusResource withStatus(String status) {
-		setStatus(status);
-        return this;
-    }
-
-    @Override
-    public String toString() {
-    	return MoreObjects.toStringHelper(this)
-    			.add("type", type)
-    			.add("resourceId", resourceId)
-                .add("status",status)
-    	        .toString();
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ImageInfoRecord.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ImageInfoRecord.java
deleted file mode 100644
index ed722ee..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ImageInfoRecord.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.dto.exploratory.ImageStatus;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.Data;
-
-@Data
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class ImageInfoRecord {
-	private final String name;
-	private final String description;
-	private final String project;
-	private final String endpoint;
-	private final String user;
-	private final String application;
-	private final String fullName;
-	private final ImageStatus status;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/KeysDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/KeysDTO.java
deleted file mode 100644
index 6f4e021..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/KeysDTO.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.resources.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-
-@AllArgsConstructor
-@Data
-public class KeysDTO {
-	private String publicKey;
-	private String privateKey;
-	private String username;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibInfoRecord.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibInfoRecord.java
deleted file mode 100644
index 4ddd6ad..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibInfoRecord.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonUnwrapped;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.util.List;
-
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
-@JsonInclude(JsonInclude.Include.NON_EMPTY)
-public class LibInfoRecord {
-    @JsonProperty
-    @JsonUnwrapped
-    private LibKey libKey;
-    
-    @JsonProperty
-    private List<LibraryStatus> status;
-
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibInstallFormDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibInstallFormDTO.java
deleted file mode 100644
index c2b8d1a..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibInstallFormDTO.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.dto.exploratory.LibInstallDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import org.hibernate.validator.constraints.NotBlank;
-import org.hibernate.validator.constraints.NotEmpty;
-
-import java.util.List;
-
-/**
- * Stores info about the installation of libraries.
- */
-@Data
-public class LibInstallFormDTO {
-    @NotBlank
-    @JsonProperty("exploratory_name")
-    private String notebookName;
-
-    @JsonProperty("computational_name")
-    private String computationalName;
-
-    @JsonProperty("project_name")
-    private String project;
-
-    @NotEmpty
-    @JsonProperty
-    private List<LibInstallDTO> libs;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibKey.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibKey.java
deleted file mode 100644
index 81d1d43..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibKey.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-@JsonInclude(JsonInclude.Include.NON_EMPTY)
-public class LibKey {
-    @JsonProperty
-    private String name;
-    @JsonProperty
-    private String version;
-    @JsonProperty
-    private String group;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibraryAutoCompleteDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibraryAutoCompleteDTO.java
deleted file mode 100644
index a74fdbc..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibraryAutoCompleteDTO.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.backendapi.domain.AutoCompleteEnum;
-import lombok.Builder;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-@Builder
-public class LibraryAutoCompleteDTO {
-	private AutoCompleteEnum autoComplete;
-	private List<LibraryDTO> libraries;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibraryDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibraryDTO.java
deleted file mode 100644
index 9a2535e..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibraryDTO.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.resources.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-
-@Getter
-@AllArgsConstructor
-@NoArgsConstructor
-public class LibraryDTO {
-	private String name;
-	private String version;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibraryStatus.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibraryStatus.java
deleted file mode 100644
index eb70c20..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/LibraryStatus.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.util.List;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-@JsonInclude(JsonInclude.Include.NON_EMPTY)
-public class LibraryStatus {
-    @JsonProperty
-    private String resource;
-    @JsonProperty
-    private String resourceType;
-    @JsonProperty
-    private String status;
-    @JsonProperty
-    private String error;
-    @JsonProperty("available_versions")
-    private List<String> availableVersions;
-    @JsonProperty("add_pkgs")
-    private List<String> addedPackages;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ProjectActionFormDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ProjectActionFormDTO.java
deleted file mode 100644
index ccdd3c4..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ProjectActionFormDTO.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-import java.util.List;
-
-@Data
-public class ProjectActionFormDTO {
-	@NotNull
-	@JsonProperty("project_name")
-	private final String projectName;
-	@NotNull
-	@JsonProperty("endpoint")
-	private final List<String> endpoints;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ProjectInfrastructureInfo.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ProjectInfrastructureInfo.java
deleted file mode 100644
index ab3f7a8..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ProjectInfrastructureInfo.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.backendapi.domain.BillingReport;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-import java.util.List;
-import java.util.Map;
-
-@AllArgsConstructor
-@Builder
-@EqualsAndHashCode
-@ToString
-public class ProjectInfrastructureInfo {
-	@JsonProperty
-	private String project;
-	@JsonProperty
-	private int billingQuoteUsed;
-	@JsonProperty
-	private Map<String, Map<String, String>> shared;
-	@JsonProperty
-	private List<UserInstanceDTO> exploratory;
-	@JsonProperty
-	private List<BillingReport> exploratoryBilling;
-	@JsonProperty
-	private List<EndpointDTO> endpoints;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/QuotaUsageDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/QuotaUsageDTO.java
deleted file mode 100644
index e611091..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/QuotaUsageDTO.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.resources.dto;
-
-import lombok.Builder;
-import lombok.Data;
-
-import java.util.Map;
-
-@Data
-@Builder
-public class QuotaUsageDTO {
-	private int totalQuotaUsed;
-	private Map<String, Integer> projectQuotas;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/SearchLibsFormDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/SearchLibsFormDTO.java
deleted file mode 100644
index ff6edb6..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/SearchLibsFormDTO.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import org.hibernate.validator.constraints.NotBlank;
-
-@Data
-public class SearchLibsFormDTO {
-    @NotBlank
-    @JsonProperty("exploratory_name")
-    private String notebookName;
-
-    @NotBlank
-    @JsonProperty("project_name")
-    private String projectName;
-
-    @NotBlank
-    @JsonProperty
-    private String group;
-
-    @NotBlank
-    @JsonProperty("start_with")
-    private String startWith;
-
-    @JsonProperty("computational_name")
-    private String computationalName;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/SparkStandaloneClusterCreateForm.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/SparkStandaloneClusterCreateForm.java
deleted file mode 100644
index 92b6270..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/SparkStandaloneClusterCreateForm.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-import org.hibernate.validator.constraints.NotBlank;
-
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class SparkStandaloneClusterCreateForm extends ComputationalCreateFormDTO {
-
-	@NotBlank
-	@JsonProperty("dataengine_instance_count")
-	private String dataEngineInstanceCount;
-
-	@NotBlank
-	@JsonProperty("dataengine_instance_shape")
-	private String dataEngineInstanceShape;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/SparkStandaloneConfiguration.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/SparkStandaloneConfiguration.java
deleted file mode 100644
index 9cc358d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/SparkStandaloneConfiguration.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Data;
-
-@Data
-@Builder
-public class SparkStandaloneConfiguration {
-    @JsonProperty("min_spark_instance_count")
-    private int minSparkInstanceCount;
-    @JsonProperty("max_spark_instance_count")
-    private int maxSparkInstanceCount;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/SystemInfoDto.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/SystemInfoDto.java
deleted file mode 100644
index 6d0d1fa..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/SystemInfoDto.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.model.systeminfo.DiskInfo;
-import com.epam.dlab.model.systeminfo.MemoryInfo;
-import com.epam.dlab.model.systeminfo.OsInfo;
-import com.epam.dlab.model.systeminfo.ProcessorInfo;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.List;
-
-@AllArgsConstructor
-@Getter
-public class SystemInfoDto {
-
-	@JsonProperty
-	private OsInfo osInfo;
-	@JsonProperty
-	private ProcessorInfo processorInfo;
-	@JsonProperty
-	private MemoryInfo memoryInfo;
-	@JsonProperty
-	private List<DiskInfo> disksInfo;
-
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UpdateGroupDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UpdateGroupDTO.java
deleted file mode 100644
index 31811c1..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UpdateGroupDTO.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.resources.dto;
-
-import lombok.Getter;
-import lombok.Setter;
-import org.hibernate.validator.constraints.NotEmpty;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-@Getter
-@Setter
-public class UpdateGroupDTO {
-    @NotEmpty
-    private String name;
-    @NotEmpty
-    private Map<String, String> roles;
-    private Set<String> users = Collections.emptySet();
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UpdateRoleGroupDto.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UpdateRoleGroupDto.java
deleted file mode 100644
index 2913712..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UpdateRoleGroupDto.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.resources.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import org.hibernate.validator.constraints.NotEmpty;
-
-import java.util.Set;
-
-@AllArgsConstructor
-@Getter
-public class UpdateRoleGroupDto {
-
-	@NotEmpty
-	private final Set<String> roleIds;
-	@NotEmpty
-	private final String group;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UpdateUserGroupDto.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UpdateUserGroupDto.java
deleted file mode 100644
index 8e3bb5f..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UpdateUserGroupDto.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.resources.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import org.hibernate.validator.constraints.NotEmpty;
-
-import java.util.Set;
-
-@AllArgsConstructor
-@Getter
-public class UpdateUserGroupDto {
-
-	@NotEmpty
-	private final String group;
-	@NotEmpty
-	private final Set<String> users;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserDTO.java
deleted file mode 100644
index 7f46612..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserDTO.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.resources.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-
-import javax.validation.constraints.Min;
-import javax.validation.constraints.NotNull;
-
-@Data
-@AllArgsConstructor
-public class UserDTO {
-	@NotNull
-	private final String name;
-	@Min(1)
-	private final Integer budget;
-	private Status status;
-
-	public enum Status {
-		ACTIVE, NOT_ACTIVE
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserGroupDto.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserGroupDto.java
deleted file mode 100644
index 8154892..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserGroupDto.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.List;
-import java.util.Set;
-
-@AllArgsConstructor
-@Getter
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class UserGroupDto {
-	private final String group;
-	private final List<UserRoleDto> roles;
-	private final Set<String> users;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserResourceInfo.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserResourceInfo.java
deleted file mode 100644
index aebe2b1..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserResourceInfo.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.dto.ResourceURL;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.model.ResourceEnum;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-@Builder
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class UserResourceInfo {
-	@JsonProperty
-	private String user;
-	@JsonProperty
-	private String project;
-	@JsonProperty
-	private String endpoint;
-	@JsonProperty("resource_type")
-	private ResourceEnum resourceType;
-	@JsonProperty("resource_name")
-	private String resourceName;
-	@JsonProperty("shape")
-	private String resourceShape;
-	@JsonProperty("status")
-	private String resourceStatus;
-	@JsonProperty("computational_resources")
-	private List<UserComputationalResource> computationalResources;
-	@JsonProperty("public_ip")
-	private String ip;
-	@JsonProperty("cloud_provider")
-	private String cloudProvider;
-	@JsonProperty("exploratory_urls")
-	private List<ResourceURL> exploratoryUrls;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserRoleDto.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserRoleDto.java
deleted file mode 100644
index 989ecf4..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserRoleDto.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.resources.dto;
-
-import com.epam.dlab.cloud.CloudProvider;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-
-@Getter
-@Setter
-@ToString
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class UserRoleDto {
-	@JsonProperty("_id")
-	private String id;
-	private String description;
-	private Type type;
-	private CloudProvider cloud;
-	private Set<String> pages;
-	private Set<String> computationals;
-	private Set<String> exploratories;
-	@JsonProperty("exploratory_shapes")
-	private Set<String> exploratoryShapes;
-	@JsonProperty("computational_shapes")
-	private Set<String> computationalShapes;
-	private Set<String> groups;
-
-	private enum Type {
-		NOTEBOOK,
-		COMPUTATIONAL,
-		NOTEBOOK_SHAPE,
-		COMPUTATIONAL_SHAPE,
-		BILLING,
-		BUCKET_BROWSER,
-		ADMINISTRATION
-	}
-
-	public static List<Type> cloudSpecificTypes() {
-		return Arrays.asList(Type.NOTEBOOK, Type.COMPUTATIONAL, Type.NOTEBOOK_SHAPE, Type.COMPUTATIONAL_SHAPE);
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/aws/AwsComputationalCreateForm.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/aws/AwsComputationalCreateForm.java
deleted file mode 100644
index 869b89d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/aws/AwsComputationalCreateForm.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.resources.dto.aws;
-
-import com.epam.dlab.backendapi.resources.dto.ComputationalCreateFormDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-import org.hibernate.validator.constraints.NotBlank;
-
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class AwsComputationalCreateForm extends ComputationalCreateFormDTO {
-
-	@NotBlank
-	@JsonProperty("emr_instance_count")
-	private String instanceCount;
-
-	@NotBlank
-	@JsonProperty("emr_master_instance_type")
-	private String masterInstanceType;
-
-	@NotBlank
-	@JsonProperty("emr_slave_instance_type")
-	private String slaveInstanceType;
-
-	@JsonProperty("emr_slave_instance_spot")
-	private Boolean slaveInstanceSpot = false;
-
-	@JsonProperty("emr_slave_instance_spot_pct_price")
-	private Integer slaveInstanceSpotPctPrice;
-
-	@NotBlank
-	@JsonProperty("emr_version")
-	private String version;
-
-
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/aws/AwsEmrConfiguration.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/aws/AwsEmrConfiguration.java
deleted file mode 100644
index 3aadfd8..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/aws/AwsEmrConfiguration.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.resources.dto.aws;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Data;
-import org.hibernate.validator.constraints.NotBlank;
-
-/**
- * Stores limits for creation of the computational resources for EMR cluster
- */
-@Data
-@Builder
-public class AwsEmrConfiguration {
-    @NotBlank
-    @JsonProperty("min_emr_instance_count")
-    private int minEmrInstanceCount;
-
-    @NotBlank
-    @JsonProperty("max_emr_instance_count")
-    private int maxEmrInstanceCount;
-
-    @NotBlank
-    @JsonProperty("min_emr_spot_instance_bid_pct")
-    private int minEmrSpotInstanceBidPct;
-
-    @NotBlank
-    @JsonProperty("max_emr_spot_instance_bid_pct")
-    private int maxEmrSpotInstanceBidPct;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/gcp/GcpComputationalCreateForm.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/gcp/GcpComputationalCreateForm.java
deleted file mode 100644
index 8b7a041..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/gcp/GcpComputationalCreateForm.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.resources.dto.gcp;
-
-import com.epam.dlab.backendapi.resources.dto.ComputationalCreateFormDTO;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.ToString;
-import org.hibernate.validator.constraints.NotBlank;
-
-@Data
-@ToString(callSuper = true)
-public class GcpComputationalCreateForm extends ComputationalCreateFormDTO {
-
-	@NotBlank
-	@JsonProperty("dataproc_master_count")
-	private String masterInstanceCount;
-
-	@NotBlank
-	@JsonProperty("dataproc_slave_count")
-	private String slaveInstanceCount;
-
-	@NotBlank
-	@JsonProperty("dataproc_preemptible_count")
-	private String preemptibleCount;
-
-	@JsonProperty("dataproc_master_instance_type")
-	private String masterInstanceType;
-
-	@JsonProperty("dataproc_slave_instance_type")
-	private String slaveInstanceType;
-
-	@NotBlank
-	@JsonProperty("dataproc_version")
-	private String version;
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/gcp/GcpDataprocConfiguration.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/gcp/GcpDataprocConfiguration.java
deleted file mode 100644
index fee6694..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/gcp/GcpDataprocConfiguration.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.resources.dto.gcp;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Builder;
-import lombok.Data;
-import org.hibernate.validator.constraints.NotBlank;
-
-/**
- * Stores limits for creation of the computational resources for Dataproc cluster
- */
-@Data
-@Builder
-public class GcpDataprocConfiguration {
-	@NotBlank
-	@JsonProperty("min_instance_count")
-	private int minInstanceCount;
-	@NotBlank
-	@JsonProperty("max_instance_count")
-	private int maxInstanceCount;
-	@NotBlank
-	@JsonProperty("min_dataproc_preemptible_instance_count")
-	private int minDataprocPreemptibleInstanceCount;
-}
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
deleted file mode 100644
index f73d25b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ComputationalResourceGcp.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * 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.resources.gcp;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
-import com.epam.dlab.backendapi.resources.dto.gcp.GcpComputationalCreateForm;
-import com.epam.dlab.backendapi.roles.RoleType;
-import com.epam.dlab.backendapi.roles.UserRoles;
-import com.epam.dlab.backendapi.service.ComputationalService;
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.gcp.computational.GcpComputationalResource;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.contracts.ComputationalAPI;
-import com.google.inject.Inject;
-import io.dropwizard.auth.Auth;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-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.List;
-
-import static com.epam.dlab.dto.UserInstanceStatus.CREATING;
-
-
-/**
- * Provides the REST API for the computational resource on GCP.
- */
-@Path("/gcp/infrastructure_provision/computational_resources")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-@Slf4j
-public class ComputationalResourceGcp implements ComputationalAPI {
-	private final SelfServiceApplicationConfiguration configuration;
-	private final ComputationalService computationalService;
-
-	@Inject
-	public ComputationalResourceGcp(SelfServiceApplicationConfiguration configuration, ComputationalService computationalService) {
-		this.configuration = configuration;
-		this.computationalService = computationalService;
-	}
-
-
-	@GET
-	@Path("/{project}/{endpoint}/templates")
-	public Response getTemplates(@Auth @Parameter(hidden = true) UserInfo userInfo, @PathParam("project") String project,
-								 @PathParam("endpoint") String endpoint) {
-		return Response.ok(computationalService.getComputationalNamesAndTemplates(userInfo, project, endpoint)).build();
-	}
-
-	/**
-	 * Asynchronously creates Dataproc cluster
-	 *
-	 * @param userInfo user info.
-	 * @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
-	 */
-	@PUT
-	@Path("dataengine-service")
-	@Operation(tags = "computational", summary = "Create dataproc cluster")
-	public Response createDataEngineService(@Auth @Parameter(hidden = true) UserInfo userInfo,
-											@Valid @NotNull @Parameter GcpComputationalCreateForm form) {
-
-		log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
-
-		if (DataEngineType.CLOUD_SERVICE == DataEngineType.fromDockerImageName(form.getImage())) {
-            validate(userInfo, form);
-            GcpComputationalResource gcpComputationalResource = GcpComputationalResource.builder()
-					.computationalName(form.getName())
-					.imageName(form.getImage())
-					.templateName(form.getTemplateName())
-					.status(CREATING.toString())
-					.masterShape(form.getMasterInstanceType())
-					.slaveShape(form.getSlaveInstanceType())
-					.slaveNumber(form.getSlaveInstanceCount())
-					.masterNumber(form.getMasterInstanceCount())
-					.preemptibleNumber(form.getPreemptibleCount())
-					.version(form.getVersion())
-					.totalInstanceCount(Integer.parseInt(form.getMasterInstanceCount()) + Integer.parseInt(form.getSlaveInstanceCount()))
-                    .build();
-            boolean resourceAdded = computationalService.createDataEngineService(userInfo, form.getName(), form, gcpComputationalResource,
-                    form.getProject(), getAuditInfo(form.getNotebookName()));
-			return resourceAdded ? Response.ok().build() : Response.status(Response.Status.FOUND).build();
-		}
-
-		throw new IllegalArgumentException("Malformed image " + form.getImage());
-	}
-
-
-	/**
-	 * Asynchronously triggers creation of Spark cluster
-	 *
-	 * @param userInfo user info.
-	 * @param form     DTO info about creation of the computational resource.
-	 * @return 200 OK - if request success, 302 Found - for duplicates.
-	 */
-	@PUT
-	@Path("dataengine")
-	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.getName(), form, form.getProject(), getAuditInfo(form.getNotebookName()))
-                ? Response.ok().build()
-                : Response.status(Response.Status.FOUND).build();
-    }
-
-
-	/**
-	 * Sends request to provisioning service for termination the computational resource for user.
-	 *
-	 * @param userInfo          user info.
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @return 200 OK if operation is successfully triggered
-	 */
-	@DELETE
-	@Path("/{projectName}/{exploratoryName}/{computationalName}/terminate")
-	public Response terminate(@Auth UserInfo userInfo,
-							  @PathParam("projectName") String projectName,
-							  @PathParam("exploratoryName") String exploratoryName,
-							  @PathParam("computationalName") String computationalName) {
-        log.debug("Terminating computational resource {} for user {}", computationalName, userInfo.getName());
-
-        computationalService.terminateComputational(userInfo, userInfo.getName(), projectName, exploratoryName, computationalName, getAuditInfo(exploratoryName));
-        return Response.ok().build();
-    }
-
-	/**
-	 * Sends request to provisioning service for stopping the computational resource for user.
-	 *
-	 * @param userInfo          user info.
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @return 200 OK if operation is successfully triggered
-	 */
-	@DELETE
-	@Path("/{project}/{exploratoryName}/{computationalName}/stop")
-	public Response stop(@Auth UserInfo userInfo,
-						 @PathParam("project") String project,
-						 @PathParam("exploratoryName") String exploratoryName,
-						 @PathParam("computationalName") String computationalName) {
-        log.debug("Stopping computational resource {} for user {}", computationalName, userInfo.getName());
-
-        computationalService.stopSparkCluster(userInfo, userInfo.getName(), project, exploratoryName, computationalName, getAuditInfo(exploratoryName));
-        return Response.ok().build();
-    }
-
-	/**
-	 * Sends request to provisioning service for starting the computational resource for user.
-	 *
-	 * @param userInfo          user info.
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @return 200 OK if operation is successfully triggered
-	 */
-	@PUT
-	@Path("/{project}/{exploratoryName}/{computationalName}/start")
-	public Response start(@Auth UserInfo userInfo,
-						  @PathParam("exploratoryName") String exploratoryName,
-						  @PathParam("computationalName") String computationalName,
-						  @PathParam("project") String project) {
-        log.debug("Starting computational resource {} for user {}", computationalName, userInfo.getName());
-
-        computationalService.startSparkCluster(userInfo, exploratoryName, computationalName, project, getAuditInfo(exploratoryName));
-        return Response.ok().build();
-    }
-
-	@PUT
-	@Path("dataengine/{projectName}/{exploratoryName}/{computationalName}/config")
-	public Response updateDataEngineConfig(@Auth UserInfo userInfo,
-										   @PathParam("projectName") String projectName,
-										   @PathParam("exploratoryName") String exploratoryName,
-										   @PathParam("computationalName") String computationalName,
-										   @Valid @NotNull List<ClusterConfig> config) {
-
-		computationalService.updateSparkClusterConfig(userInfo, projectName, exploratoryName, computationalName, config,
-				String.format(AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE, computationalName, exploratoryName));
-		return Response.ok().build();
-	}
-
-	@GET
-	@Path("/{projectName}/{exploratoryName}/{computationalName}/config")
-	public Response getClusterConfig(@Auth UserInfo userInfo,
-									 @PathParam("projectName") String projectName,
-									 @PathParam("exploratoryName") String exploratoryName,
-									 @PathParam("computationalName") String computationalName) {
-		return Response.ok(computationalService.getClusterConfig(userInfo, projectName, exploratoryName, computationalName)).build();
-	}
-
-	private void validate(@Auth UserInfo userInfo, GcpComputationalCreateForm formDTO) {
-		if (!UserRoles.checkAccess(userInfo, RoleType.COMPUTATIONAL, formDTO.getImage(), userInfo.getRoles())) {
-			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());
-		}
-
-		int slaveInstanceCount = Integer.parseInt(formDTO.getSlaveInstanceCount());
-		int masterInstanceCount = Integer.parseInt(formDTO.getMasterInstanceCount());
-		final int total = slaveInstanceCount + masterInstanceCount;
-		if (total < configuration.getMinInstanceCount()
-				|| total > configuration.getMaxInstanceCount()) {
-			log.debug("Creating computational resource {} for user {} fail: Limit exceeded to creation total " +
-							"instances. Minimum is {}, maximum is {}", formDTO.getName(), userInfo.getName(),
-					configuration.getMinInstanceCount(), configuration.getMaxInstanceCount());
-			throw new DlabException("Limit exceeded to creation slave instances. Minimum is " + configuration
-					.getMinInstanceCount() + ", maximum is " + configuration.getMaxInstanceCount());
-		}
-
-        final int preemptibleInstanceCount = Integer.parseInt(formDTO.getPreemptibleCount());
-        if (preemptibleInstanceCount < configuration.getMinDataprocPreemptibleCount()) {
-            log.debug("Creating computational resource {} for user {} fail: Limit exceeded to creation preemptible " +
-                            "instances. Minimum is {}",
-                    formDTO.getName(), userInfo.getName(), configuration.getMinDataprocPreemptibleCount());
-            throw new DlabException("Limit exceeded to creation preemptible instances. " +
-                    "Minimum is " + configuration.getMinDataprocPreemptibleCount());
-
-        }
-    }
-
-    private String getAuditInfo(String exploratoryName) {
-        return String.format(AUDIT_MESSAGE, exploratoryName);
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/GcpOauthResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/GcpOauthResource.java
deleted file mode 100644
index 426633d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/GcpOauthResource.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.resources.gcp;
-
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.gcp.auth.GcpOauth2AuthorizationCodeResponse;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.auth.contract.SecurityAPI;
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.net.URI;
-
-@Path("/user/gcp")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class GcpOauthResource {
-
-	@Inject
-	@Named(ServiceConsts.SECURITY_SERVICE_NAME)
-	private RESTService securityService;
-
-
-	@GET
-	@Path("/init")
-	public Response redirectedUrl() {
-		return Response
-				.seeOther(URI.create(securityService.get(SecurityAPI.INIT_LOGIN_OAUTH_GCP, String.class)))
-				.build();
-	}
-
-	@GET
-	@Path("/oauth")
-	public Response login(@QueryParam("code") String code, @QueryParam("state") String state,
-						  @QueryParam("error") String error) {
-		return securityService.post(SecurityAPI.LOGIN_OAUTH,
-				new GcpOauth2AuthorizationCodeResponse(code, state, error),
-				Response.class);
-	}
-
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/RoleType.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/RoleType.java
deleted file mode 100644
index 4ec40d2..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/RoleType.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.roles;
-
-/**
- * Types of roles.
- */
-public enum RoleType {
-	COMPUTATIONAL("computationals"),
-	EXPLORATORY("exploratories"),
-	EXPLORATORY_SHAPES("exploratory_shapes"),
-	COMPUTATIONAL_SHAPES("computational_shapes"),
-	PAGE("pages");
-
-	private String nodeName;
-
-	RoleType(String nodeName) {
-		this.nodeName = nodeName;
-	}
-
-	public static RoleType of(String name) {
-		if (name != null) {
-			for (RoleType value : RoleType.values()) {
-				if (name.equalsIgnoreCase(value.toString())) {
-					return value;
-				}
-			}
-		}
-		return null;
-	}
-
-	/**
-	 * Return name of node in JSON for type.
-	 */
-	public String getNodeName() {
-		return nodeName;
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/UserRole.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/UserRole.java
deleted file mode 100644
index bb16414..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/UserRole.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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.roles;
-
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
-
-import javax.annotation.Nonnull;
-import java.util.Comparator;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Describe role.
- */
-public class UserRole implements Comparable<UserRole> {
-
-	private final String id;
-	/**
-	 * Type of role.
-	 */
-	private final RoleType type;
-
-	/**
-	 * Name of role.
-	 */
-	private final String name;
-
-	/**
-	 * Names of external groups.
-	 */
-	private final Set<String> groups;
-
-	/**
-	 * Name of DLab's users.
-	 */
-	private final Set<String> users;
-
-	/**
-	 * Instantiate the role.
-	 *
-	 * @param id
-	 * @param type   type of role.
-	 * @param name   the name of role.
-	 * @param groups the names of external groups.
-	 * @param users  the name of DLab's users.
-	 */
-	UserRole(String id, RoleType type, String name, Set<String> groups, Set<String> users) {
-		this.id = id;
-		this.type = type;
-		this.name = name;
-		this.groups = groups;
-		this.users = users;
-	}
-
-	/**
-	 * Return the type of role.
-	 */
-	public RoleType getType() {
-		return type;
-	}
-
-	/**
-	 * Return the name of role.
-	 */
-	public String getName() {
-		return name;
-	}
-
-	/**
-	 * Return the names of external groups.
-	 */
-	public Set<String> getGroups() {
-		return groups;
-	}
-
-	/**
-	 * Return the name of DLab's users.
-	 */
-	public Set<String> getUsers() {
-		return users;
-	}
-
-	public String getId() {
-		return id;
-	}
-
-	@Override
-	public int compareTo(@Nonnull UserRole o) {
-		return Comparator.comparing(UserRole::getType)
-				.thenComparing(UserRole::getName)
-				.thenComparing(UserRole::getId, Comparator.nullsLast(String::compareToIgnoreCase))
-				.compare(this, o);
-	}
-
-	private ToStringHelper toStringHelper(Object self) {
-		return MoreObjects.toStringHelper(self)
-				.add("type", type)
-				.add("name", name)
-				.add("groups", groups)
-				.add("users", users);
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		if (this == o) {
-			return true;
-		}
-		if (o == null || getClass() != o.getClass()) {
-			return false;
-		}
-		UserRole userRole = (UserRole) o;
-		return this.id.equals(userRole.getId()) && this.type.equals(userRole.getType()) && this.name.equals(userRole.getName());
-	}
-
-	@Override
-	public int hashCode() {
-		return Objects.hash(type, name);
-	}
-
-	@Override
-	public String toString() {
-		return toStringHelper(this).toString();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/UserRoles.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/UserRoles.java
deleted file mode 100644
index 9be9578..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/UserRoles.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * 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.roles;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.SecurityDAO;
-import com.epam.dlab.exceptions.DlabException;
-import com.google.common.base.MoreObjects;
-import com.mongodb.client.FindIterable;
-import org.bson.Document;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Provides user roles access to features.
- */
-public class UserRoles {
-	private static final Logger LOGGER = LoggerFactory.getLogger(UserRoles.class);
-
-	private static final String ANY_USER = "$anyuser";
-	/**
-	 * Node name of groups.
-	 */
-	private static final String GROUPS = "groups";
-	/**
-	 * Node name of user.
-	 */
-	private static final String USERS = "users";
-	private static final String PROJECT_ADMIN_ROLE_NAME = "projectAdmin";
-	private static final String ADMIN_ROLE_NAME = "admin";
-	/**
-	 * Single instance of the user roles.
-	 */
-	private static UserRoles userRoles = null;
-	/**
-	 * List of roles.
-	 */
-	private List<UserRole> roles = null;
-	private Map<String, Set<String>> userGroups;
-
-	/**
-	 * Default access to features if the role is not defined.
-	 */
-	private boolean defaultAccess = false;
-
-	/**
-	 * Initialize user roles for all users.
-	 *
-	 * @param dao security DAO.
-	 */
-	public static void initialize(SecurityDAO dao, boolean defaultAccess) {
-		LOGGER.trace("Loading roles from database...");
-		if (userRoles == null) {
-			userRoles = new UserRoles();
-		}
-		userRoles.load(dao, defaultAccess);
-		LOGGER.trace("New roles are	: {}", getRoles());
-	}
-
-	/**
-	 * Return the list of roles for all users.
-	 */
-	public static List<UserRole> getRoles() {
-		return (userRoles == null ? null : userRoles.roles());
-	}
-
-	/**
-	 * Check access for user to the role.
-	 *
-	 * @param userInfo user info.
-	 * @param type     the type of role.
-	 * @param name     the name of role.
-	 * @param roles
-	 * @return boolean value
-	 */
-	public static boolean checkAccess(UserInfo userInfo, RoleType type, String name, Collection<String> roles) {
-		return checkAccess(userInfo, type, name, true, roles);
-	}
-
-	public static boolean isProjectAdmin(UserInfo userInfo) {
-		final List<UserRole> roles = UserRoles.getRoles();
-		return roles == null || roles.stream().anyMatch(r -> PROJECT_ADMIN_ROLE_NAME.equalsIgnoreCase(r.getId()) &&
-				(userRoles.hasAccessByGroup(userInfo, userInfo.getRoles(), r.getGroups()) || userRoles.hasAccessByUserName(userInfo, r)));
-	}
-
-	public static boolean isProjectAdmin(UserInfo userInfo, Set<String> groups) {
-		final List<UserRole> roles = UserRoles.getRoles();
-		return roles == null || roles.stream().anyMatch(r -> PROJECT_ADMIN_ROLE_NAME.equalsIgnoreCase(r.getId()) &&
-				(userRoles.hasAccessByGroup(userInfo, userInfo.getRoles(), retainGroups(r.getGroups(), groups)) || userRoles.hasAccessByUserName(userInfo, r)));
-	}
-
-	public static boolean isAdmin(UserInfo userInfo) {
-		final List<UserRole> roles = UserRoles.getRoles();
-		return roles == null || roles.stream().anyMatch(r -> ADMIN_ROLE_NAME.equalsIgnoreCase(r.getId()) &&
-				(userRoles.hasAccessByGroup(userInfo, userInfo.getRoles(), r.getGroups()) || userRoles.hasAccessByUserName(userInfo, r)));
-	}
-
-	/**
-	 * Check access for user to the role.
-	 *
-	 * @param roles
-	 * @param userInfo user info.
-	 * @param type     the type of role.
-	 * @param name     the name of role.
-	 * @return boolean value
-	 */
-	public static boolean checkAccess(UserInfo userInfo, RoleType type, String name, boolean useDefault,
-									  Collection<String> roles) {
-		return (userRoles == null || userRoles.hasAccess(userInfo, type, name, useDefault, roles));
-	}
-
-	/**
-	 * Loading the user roles for all users from Mongo database.
-	 *
-	 * @param dao security DAO.
-	 */
-	private synchronized void load(SecurityDAO dao, boolean defaultAccess) {
-		this.defaultAccess = defaultAccess;
-		try {
-			FindIterable<Document> docs = dao.getRoles();
-			roles = new ArrayList<>();
-			for (Document d : docs) {
-				Set<String> groups = getAndRemoveSet(d, GROUPS);
-				Set<String> users = getAndRemoveSet(d, USERS);
-				String id = d.getString("_id");
-				for (RoleType type : RoleType.values()) {
-					@SuppressWarnings("unchecked")
-					List<String> names = d.get(type.getNodeName(), ArrayList.class);
-					if (names != null) {
-						for (String name : names) {
-							append(type, name, groups, users, id);
-						}
-					}
-				}
-			}
-			userGroups = dao.getGroups();
-		} catch (Exception e) {
-			throw new DlabException("Cannot load roles from database. " + e.getLocalizedMessage(), e);
-		}
-	}
-
-	private synchronized List<UserRole> roles() {
-		return roles;
-	}
-
-	/**
-	 * Append new role to the list if role not exists in list an return it, otherwise return
-	 * existence role.
-	 *
-	 * @param type   type of role.
-	 * @param name   the name of role.
-	 * @param groups the names of external groups.
-	 * @param users  the name of DLab's users.
-	 * @param id
-	 * @return role.
-	 */
-	private UserRole append(RoleType type, String name, Set<String> groups, Set<String> users, String id) {
-		UserRole item = new UserRole(id, type, name, groups, users);
-		synchronized (roles) {
-			int index = Collections.binarySearch(roles, item);
-			if (index < 0) {
-				index = -index;
-				if (index > roles.size()) {
-					roles.add(item);
-				} else {
-					roles.add(index - 1, item);
-				}
-			}
-		}
-		return item;
-	}
-
-	/**
-	 * Find and return role by type and name.
-	 *
-	 * @param type type of role.
-	 * @param name the name of role.
-	 * @return list of UserRole
-	 */
-	private Set<String> getGroups(RoleType type, String name) {
-		synchronized (roles) {
-			return roles
-					.stream()
-					.filter(r -> type == r.getType() && name.equalsIgnoreCase(r.getName()))
-					.map(UserRole::getGroups)
-					.flatMap(Collection::stream)
-					.collect(Collectors.toSet());
-		}
-	}
-
-	/**
-	 * Find and return a list by key from JSON document, otherwise return <b>null</b>.
-	 *
-	 * @param document the document.
-	 * @param key      the name of node.
-	 */
-	private Set<String> getAndRemoveSet(Document document, String key) {
-		Object o = document.get(key);
-		if (!(o instanceof ArrayList)) {
-			return Collections.emptySet();
-		}
-
-		@SuppressWarnings("unchecked")
-		List<String> list = (List<String>) o;
-		if (list.isEmpty()) {
-			return Collections.emptySet();
-		}
-
-		Set<String> set = new HashSet<>();
-		for (String value : list) {
-			set.add(value.toLowerCase());
-		}
-		document.remove(key);
-		return set;
-	}
-
-	/**
-	 * Check access for user to the role.
-	 *
-	 * @param userInfo   user info.
-	 * @param type       the type of role.
-	 * @param name       the name of role.
-	 * @param useDefault true/false
-	 * @param roles
-	 * @return boolean value
-	 */
-	private boolean hasAccess(UserInfo userInfo, RoleType type, String name, boolean useDefault,
-							  Collection<String> roles) {
-		if (userRoles == null) {
-			return true;
-		}
-		LOGGER.trace("Check access for user {} with groups {} to {}/{}", userInfo.getName(), userInfo.getRoles(),
-				type, name);
-		Set<String> groups = getGroups(type, name);
-		if (groups == null || groups.isEmpty()) {
-			return checkDefault(useDefault);
-		}
-		if (hasAccessByGroup(userInfo, roles, groups)) {
-			return true;
-		}
-		LOGGER.trace("Access denied for user {} to {}/{}", userInfo.getName(), type, name);
-		return false;
-	}
-
-	private boolean hasAccessByGroup(UserInfo userInfo, Collection<String> userRoles, Collection<String> groups) {
-		if (groups != null) {
-			if (groups.contains(ANY_USER)) {
-				return true;
-			}
-			for (String group : userRoles) {
-				if (group != null && groups.contains(group.toLowerCase())) {
-					LOGGER.trace("Got access by group {}", group);
-					return true;
-				}
-			}
-
-			final Optional<String> group = groups
-					.stream()
-					.filter(g -> userGroups.getOrDefault(g, Collections.emptySet()).contains(userInfo.getName().toLowerCase()))
-					.findAny();
-			if (group.isPresent()) {
-				LOGGER.trace("Got access by local group {}", group.get());
-				return true;
-			}
-		}
-		return false;
-	}
-
-	private boolean hasAccessByUserName(UserInfo userInfo, UserRole role) {
-		if (role.getUsers() != null &&
-				userInfo.getName() != null &&
-				(role.getUsers().contains(ANY_USER) ||
-						role.getUsers().contains(userInfo.getName().toLowerCase()))) {
-			LOGGER.trace("Got access by name");
-			return true;
-		}
-		return false;
-	}
-
-	private boolean checkDefault(boolean useDefault) {
-		if (useDefault) {
-			LOGGER.trace("Got default access {}", defaultAccess);
-			return defaultAccess;
-		} else {
-			return false;
-		}
-	}
-
-	private static Set<String> retainGroups(Set<String> groups1, Set<String> groups2) {
-		Set<String> result = groups2
-				.stream()
-				.map(String::toLowerCase)
-				.collect(Collectors.toSet());
-		result.retainAll(groups1);
-
-		return result;
-	}
-
-	@Override
-	public String toString() {
-		return MoreObjects.toStringHelper(roles)
-				.addValue(roles)
-				.toString();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckApplicationQuoteScheduler.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckApplicationQuoteScheduler.java
deleted file mode 100644
index bca047c..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckApplicationQuoteScheduler.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.schedulers;
-
-import com.epam.dlab.backendapi.dao.BillingDAO;
-import com.epam.dlab.backendapi.schedulers.internal.Scheduled;
-import com.epam.dlab.backendapi.service.EnvironmentService;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-
-@Scheduled("checkQuoteScheduler")
-@Slf4j
-public class CheckApplicationQuoteScheduler implements Job {
-	@Inject
-	private BillingDAO billingDAO;
-	@Inject
-	private EnvironmentService environmentService;
-
-	@Override
-	public void execute(JobExecutionContext context) {
-		if (billingDAO.isBillingQuoteReached()) {
-			log.warn("Stopping all environments because of reaching budget quote");
-			environmentService.stopAll();
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckInactivityScheduledJob.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckInactivityScheduledJob.java
deleted file mode 100644
index 482576a..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckInactivityScheduledJob.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.schedulers;
-
-import com.epam.dlab.backendapi.schedulers.internal.Scheduled;
-import com.epam.dlab.backendapi.service.InactivityService;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-
-/**
- * There realized integration with Quartz scheduler framework and defined check cluster inactivity scheduler job which
- * executes every time specified. If in 'self-service.yml' option 'clusterInactivityCheckerEnabled' equals 'true' then
- * this job we be executing every time predefined in option 'clusterInactivityCheckingTimeout'. Otherwise, it will
- * never execute.
- */
-@Slf4j
-@Scheduled("inactivity")
-public class CheckInactivityScheduledJob implements Job {
-
-	@Inject
-	private InactivityService inactivityService;
-
-	@Override
-	public void execute(JobExecutionContext context) {
-		log.trace("Starting check inactivity job");
-		inactivityService.updateRunningResourcesLastActivity();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckProjectQuoteScheduler.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckProjectQuoteScheduler.java
deleted file mode 100644
index 2dc499f..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckProjectQuoteScheduler.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.schedulers;
-
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.schedulers.internal.Scheduled;
-import com.epam.dlab.backendapi.service.BillingService;
-import com.epam.dlab.backendapi.service.EnvironmentService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-
-@Scheduled("checkProjectQuoteScheduler")
-@Slf4j
-public class CheckProjectQuoteScheduler implements Job {
-
-	@Inject
-	private BillingService billingService;
-	@Inject
-	private EnvironmentService environmentService;
-	@Inject
-	private ProjectService projectService;
-
-	@Override
-	public void execute(JobExecutionContext context) {
-		projectService.getProjects()
-				.stream()
-				.map(ProjectDTO::getName)
-				.filter(billingService::isProjectQuoteReached)
-				.peek(p -> log.debug("Stopping {} project env because of reaching user billing quote", p))
-				.forEach(environmentService::stopProjectEnvironment);
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckUserQuoteScheduler.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckUserQuoteScheduler.java
deleted file mode 100644
index 1e2e7f4..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckUserQuoteScheduler.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.schedulers;
-
-import com.epam.dlab.backendapi.dao.BillingDAO;
-import com.epam.dlab.backendapi.resources.dto.UserDTO;
-import com.epam.dlab.backendapi.schedulers.internal.Scheduled;
-import com.epam.dlab.backendapi.service.EnvironmentService;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-
-@Scheduled("checkUserQuoteScheduler")
-@Slf4j
-public class CheckUserQuoteScheduler implements Job {
-
-	@Inject
-	private BillingDAO billingDAO;
-	@Inject
-	private EnvironmentService environmentService;
-
-	@Override
-	public void execute(JobExecutionContext context) {
-		environmentService.getUsers()
-				.stream()
-				.map(UserDTO::getName)
-				.filter(billingDAO::isUserQuoteReached)
-				.peek(u -> log.warn("Stopping {} user env because of reaching user billing quote", u))
-				.forEach(environmentService::stopEnvironmentWithServiceAccount);
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/billing/BillingScheduler.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/billing/BillingScheduler.java
deleted file mode 100644
index ad3ffcc..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/billing/BillingScheduler.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.schedulers.billing;
-
-import com.epam.dlab.backendapi.schedulers.internal.Scheduled;
-import com.epam.dlab.backendapi.service.BillingService;
-import com.epam.dlab.backendapi.service.SecurityService;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-
-@Scheduled("billingScheduler")
-@Slf4j
-public class BillingScheduler implements Job {
-
-    private final BillingService billingService;
-    private final SecurityService securityService;
-
-    @Inject
-    public BillingScheduler(BillingService billingService, SecurityService securityService) {
-        this.billingService = billingService;
-        this.securityService = securityService;
-    }
-
-    @Override
-    public void execute(JobExecutionContext jobExecutionContext) {
-        log.info("Trying to update billing");
-        try {
-            billingService.updateRemoteBillingData(securityService.getServiceAccountInfo("admin"));
-        } catch (Exception e) {
-            log.error("Something went wrong {}", e.getMessage(), e);
-        }
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/computational/StartComputationalJob.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/computational/StartComputationalJob.java
deleted file mode 100644
index 5a6eb11..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/computational/StartComputationalJob.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.schedulers.computational;
-
-import com.epam.dlab.backendapi.schedulers.internal.Scheduled;
-import com.epam.dlab.backendapi.service.SchedulerJobService;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-
-/**
- * There realized integration with Quartz scheduler framework and defined start computational resource scheduler job
- * which executes every time specified.
- */
-@Slf4j
-@Scheduled("startComputationalScheduler")
-public class StartComputationalJob implements Job {
-
-	@Inject
-	private SchedulerJobService schedulerJobService;
-
-	@Override
-	public void execute(JobExecutionContext jobExecutionContext) {
-		schedulerJobService.startComputationalByScheduler();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/computational/StopComputationalJob.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/computational/StopComputationalJob.java
deleted file mode 100644
index 3825d08..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/computational/StopComputationalJob.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.schedulers.computational;
-
-import com.epam.dlab.backendapi.schedulers.internal.Scheduled;
-import com.epam.dlab.backendapi.service.SchedulerJobService;
-import com.google.inject.Inject;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-
-/**
- * There realized integration with Quartz scheduler framework and defined stop computational resource scheduler job
- * which executes every time specified.
- */
-@Scheduled("stopComputationalScheduler")
-public class StopComputationalJob implements Job {
-
-	@Inject
-	private SchedulerJobService schedulerJobService;
-
-	@Override
-	public void execute(JobExecutionContext jobExecutionContext) {
-		schedulerJobService.stopComputationalByScheduler();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/computational/TerminateComputationalJob.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/computational/TerminateComputationalJob.java
deleted file mode 100644
index 765a6e8..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/computational/TerminateComputationalJob.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.schedulers.computational;
-
-import com.epam.dlab.backendapi.schedulers.internal.Scheduled;
-import com.epam.dlab.backendapi.service.SchedulerJobService;
-import com.google.inject.Inject;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-
-@Scheduled("terminateComputationalScheduler")
-public class TerminateComputationalJob implements Job {
-	private final SchedulerJobService schedulerJobService;
-
-	@Inject
-	public TerminateComputationalJob(SchedulerJobService schedulerJobService) {
-		this.schedulerJobService = schedulerJobService;
-	}
-
-	@Override
-	public void execute(JobExecutionContext context) {
-		schedulerJobService.terminateComputationalByScheduler();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/endpoint/CheckEndpointStatusScheduler.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/endpoint/CheckEndpointStatusScheduler.java
deleted file mode 100644
index 02d109d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/endpoint/CheckEndpointStatusScheduler.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.schedulers.endpoint;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.schedulers.internal.Scheduled;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.SecurityService;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-
-@Scheduled("checkEndpointStatusScheduler")
-@Slf4j
-public class CheckEndpointStatusScheduler implements Job {
-
-    @Inject
-    private EndpointService endpointService;
-    @Inject
-    private SecurityService securityService;
-
-    @Override
-    public void execute(JobExecutionContext jobExecutionContext) {
-        UserInfo serviceUser = securityService.getServiceAccountInfo("admin");
-        endpointService.getEndpoints().stream()
-                .filter(endpoint -> checkUrlWithStatus(serviceUser, endpoint))
-                .forEach(this::changeStatusToOpposite);
-    }
-
-    private boolean checkUrlWithStatus(UserInfo serviceUser, EndpointDTO endpoint) {
-        try {
-            endpointService.checkUrl(serviceUser, endpoint.getUrl());
-        } catch (Exception e) {
-            log.warn("Failed connecting to endpoint {}, url: '{}'. {}", endpoint.getName(), endpoint.getUrl(), e.getMessage(), e);
-            return endpoint.getStatus() == EndpointDTO.EndpointStatus.ACTIVE;
-        }
-        return endpoint.getStatus() == EndpointDTO.EndpointStatus.INACTIVE;
-    }
-
-    private void changeStatusToOpposite(EndpointDTO endpoint) {
-        if (endpoint.getStatus() == EndpointDTO.EndpointStatus.ACTIVE) {
-            endpointService.updateEndpointStatus(endpoint.getName(), EndpointDTO.EndpointStatus.INACTIVE);
-        } else {
-            endpointService.updateEndpointStatus(endpoint.getName(), EndpointDTO.EndpointStatus.ACTIVE);
-        }
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/exploratory/StartExploratoryJob.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/exploratory/StartExploratoryJob.java
deleted file mode 100644
index 63fbee3..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/exploratory/StartExploratoryJob.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.schedulers.exploratory;
-
-import com.epam.dlab.backendapi.schedulers.internal.Scheduled;
-import com.epam.dlab.backendapi.service.SchedulerJobService;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-
-/**
- * There realized integration with Quartz scheduler framework and defined start exploratory scheduler job which
- * executes every time specified.
- */
-@Slf4j
-@Scheduled("startExploratoryScheduler")
-public class StartExploratoryJob implements Job {
-
-	@Inject
-	private SchedulerJobService schedulerJobService;
-
-	@Override
-	public void execute(JobExecutionContext jobExecutionContext) {
-		schedulerJobService.startExploratoryByScheduler();
-	}
-
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/exploratory/StopExploratoryJob.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/exploratory/StopExploratoryJob.java
deleted file mode 100644
index 576a85e..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/exploratory/StopExploratoryJob.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.schedulers.exploratory;
-
-import com.epam.dlab.backendapi.schedulers.internal.Scheduled;
-import com.epam.dlab.backendapi.service.SchedulerJobService;
-import com.google.inject.Inject;
-import lombok.extern.slf4j.Slf4j;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-
-/**
- * There realized integration with Quartz scheduler framework and defined stop exploratory scheduler job which
- * executes every time specified.
- */
-@Slf4j
-@Scheduled("stopExploratoryScheduler")
-public class StopExploratoryJob implements Job {
-
-	@Inject
-	private SchedulerJobService schedulerJobService;
-
-	@Override
-	public void execute(JobExecutionContext jobExecutionContext) {
-		schedulerJobService.stopExploratoryByScheduler();
-	}
-
-}
-
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/internal/ManagedScheduler.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/internal/ManagedScheduler.java
deleted file mode 100644
index c7eddd8..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/internal/ManagedScheduler.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.schedulers.internal;
-
-import com.epam.dlab.backendapi.SelfServiceApplication;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.domain.SchedulerConfigurationData;
-import com.epam.dlab.exceptions.DlabException;
-import com.fiestacabin.dropwizard.quartz.GuiceJobFactory;
-import com.google.inject.Inject;
-import io.dropwizard.lifecycle.Managed;
-import lombok.extern.slf4j.Slf4j;
-import org.quartz.*;
-import org.reflections.Reflections;
-import org.reflections.scanners.SubTypesScanner;
-
-import java.util.Optional;
-
-import static org.quartz.JobBuilder.newJob;
-import static org.quartz.TriggerBuilder.newTrigger;
-
-@Slf4j
-public class ManagedScheduler implements Managed {
-	private final Scheduler scheduler;
-	private final GuiceJobFactory jobFactory;
-	private final SelfServiceApplicationConfiguration config;
-
-	@Inject
-	public ManagedScheduler(Scheduler scheduler, GuiceJobFactory jobFactory,
-							SelfServiceApplicationConfiguration config) {
-		this.scheduler = scheduler;
-		this.jobFactory = jobFactory;
-		this.config = config;
-	}
-
-	@Override
-	public void start() throws Exception {
-		scheduler.setJobFactory(jobFactory);
-		scheduler.start();
-
-		new Reflections(SelfServiceApplication.class.getPackage().getName(), new SubTypesScanner())
-				.getSubTypesOf(Job.class)
-				.forEach(scheduledClass ->
-						Optional.ofNullable(scheduledClass.getAnnotation(Scheduled.class))
-								.filter(this::triggerNotExist)
-								.ifPresent(scheduleAnn -> schedule(scheduledClass, scheduleAnn)));
-
-	}
-
-	@Override
-	public void stop() throws Exception {
-		scheduler.shutdown();
-	}
-
-	private Trigger getTrigger(SchedulerConfigurationData schedulerConfig, String schedulerName) {
-		return newTrigger()
-				.withIdentity(schedulerName)
-				.withSchedule(CronScheduleBuilder.cronSchedule(schedulerConfig.getCron()))
-				.startNow()
-				.build();
-	}
-
-	private void schedule(Class<? extends Job> scheduledClass, Scheduled scheduleAnn) {
-		final String schedulerName = scheduleAnn.value();
-		final SchedulerConfigurationData schedulerConfig =
-				Optional.ofNullable(config.getSchedulers().get(schedulerName)).orElseThrow(() -> new IllegalStateException(
-						"There is no configuration provided for scheduler with name " + schedulerName));
-		if (schedulerConfig.isEnabled()) {
-			scheduleJob(newJob(scheduledClass).build(), schedulerConfig, scheduleAnn.value());
-		}
-	}
-
-	private void scheduleJob(JobDetail job, SchedulerConfigurationData schedulerConfig, String schedulerName) {
-		try {
-			final Trigger trigger = getTrigger(schedulerConfig, schedulerName);
-			scheduler.scheduleJob(job, trigger);
-			log.info("Scheduled job {} with trigger {}", job, trigger);
-		} catch (SchedulerException e) {
-			log.error("Can't schedule job due to: {}", e.getMessage());
-			throw new DlabException("Can't schedule job due to: " + e.getMessage(), e);
-		}
-	}
-
-	private boolean triggerNotExist(Scheduled scheduled) {
-		try {
-			return !scheduler.checkExists(new TriggerKey(scheduled.value()));
-		} catch (SchedulerException e) {
-			log.error("Can not check if trigger exist due to: {}", e.getMessage());
-			throw new DlabException("Can not check if trigger exist due to: {}" + e.getMessage(), e);
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/internal/Scheduled.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/internal/Scheduled.java
deleted file mode 100644
index 50fca1c..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/internal/Scheduled.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.schedulers.internal;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation is used as alternative to {@link com.fiestacabin.dropwizard.quartz.Scheduled}
- * and allow to use scheduler configuration from application config
- * }
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface Scheduled {
-	/**
-	 * @return scheduler name
-	 */
-	String value();
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AccessKeyService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AccessKeyService.java
deleted file mode 100644
index 2c84226..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AccessKeyService.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.KeysDTO;
-
-@FunctionalInterface
-public interface AccessKeyService {
-	KeysDTO generateKeys(UserInfo userInfo);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ApplicationSettingService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ApplicationSettingService.java
deleted file mode 100644
index 5a434b5..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ApplicationSettingService.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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 java.util.Map;
-
-public interface ApplicationSettingService {
-
-	void removeMaxBudget();
-
-	void setMaxBudget(Long maxBudget);
-
-	Map<String, Object> getSettings();
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ApplicationSettingServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ApplicationSettingServiceImpl.java
deleted file mode 100644
index fcdd28a..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ApplicationSettingServiceImpl.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.dao.MongoSetting;
-import com.epam.dlab.backendapi.dao.SettingsDAO;
-import com.google.inject.Inject;
-
-import java.util.Map;
-
-public class ApplicationSettingServiceImpl implements ApplicationSettingService {
-	@Inject
-	private SettingsDAO settingsDAO;
-
-	@Override
-	public void removeMaxBudget() {
-		settingsDAO.removeSetting(MongoSetting.CONF_MAX_BUDGET);
-	}
-
-	@Override
-	public void setMaxBudget(Long maxBudget) {
-		settingsDAO.setMaxBudget(maxBudget);
-	}
-
-	@Override
-	public Map<String, Object> getSettings() {
-		return settingsDAO.getSettings();
-	}
-}
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
deleted file mode 100644
index 81bbec7..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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;
-import com.epam.dlab.backendapi.domain.AuditDTO;
-import com.epam.dlab.backendapi.domain.AuditPaginationDTO;
-
-import java.util.List;
-
-public interface AuditService {
-    void save(AuditDTO audit);
-
-    void save(String user, AuditCreateDTO audit);
-
-    List<AuditPaginationDTO> getAudit(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd, int pageNumber, int pageSize);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BackupService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BackupService.java
deleted file mode 100644
index af8f0c1..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BackupService.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.BackupInfoRecord;
-import com.epam.dlab.dto.backup.EnvBackupDTO;
-import com.epam.dlab.dto.backup.EnvBackupStatus;
-
-import java.util.List;
-
-public interface BackupService {
-	String createBackup(EnvBackupDTO dto, UserInfo userInfo);
-
-	void updateStatus(EnvBackupDTO dto, String user, EnvBackupStatus status);
-
-	List<BackupInfoRecord> getBackups(String userName);
-
-	BackupInfoRecord getBackup(String userName, String id);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BillingService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BillingService.java
deleted file mode 100644
index 7291cc7..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BillingService.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.BillingReport;
-import com.epam.dlab.backendapi.resources.dto.BillingFilter;
-import com.epam.dlab.backendapi.resources.dto.QuotaUsageDTO;
-
-import java.util.List;
-
-public interface BillingService {
-	BillingReport getBillingReport(UserInfo userInfo, BillingFilter filter);
-
-	String downloadReport(UserInfo userInfo, BillingFilter filter);
-
-	BillingReport getExploratoryBillingData(String project, String endpoint, String exploratoryName, List<String> compNames);
-
-	void updateRemoteBillingData(UserInfo userInfo);
-
-	QuotaUsageDTO getQuotas(UserInfo userInfo);
-
-	boolean isProjectQuoteReached(String project);
-
-	int getBillingProjectQuoteUsed(String project);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BucketService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BucketService.java
deleted file mode 100644
index 1173fea..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/BucketService.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.dto.bucket.BucketDTO;
-
-import javax.servlet.http.HttpServletResponse;
-import java.io.InputStream;
-import java.util.List;
-
-public interface BucketService {
-    List<BucketDTO> getObjects(UserInfo userInfo, String bucket, String endpoint);
-
-    void uploadObject(UserInfo userInfo, String bucket, String object, String endpoint, InputStream inputStream, String contentType, long fileSize, String auditInfo);
-
-    void uploadFolder(UserInfo userInfo, String bucket, String folder, String endpoint, String auditInfo);
-
-    void downloadObject(UserInfo userInfo, String bucket, String object, String endpoint, HttpServletResponse resp, String auditInfo);
-
-    void deleteObjects(UserInfo userInfo, String bucket, List<String> objects, String endpoint, String auditInfo);
-}
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
deleted file mode 100644
index e284da2..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ComputationalService.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.ComputationalCreateFormDTO;
-import com.epam.dlab.backendapi.resources.dto.ComputationalTemplatesDTO;
-import com.epam.dlab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-
-import java.util.List;
-import java.util.Optional;
-
-public interface ComputationalService {
-	ComputationalTemplatesDTO getComputationalNamesAndTemplates(UserInfo user, String project, String endpoint);
-
-	/**
-     * Asynchronously triggers creation of Spark cluster
-     *
-     * @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, String resourceName, SparkStandaloneClusterCreateForm form, String project, 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 computationalName computational name
-     * @param auditInfo         additional info for audit
-     */
-    void terminateComputational(UserInfo userInfo, String resourceCreator, String project, String exploratoryName, String computationalName, String auditInfo);
-
-    boolean createDataEngineService(UserInfo userInfo, String resourceName, ComputationalCreateFormDTO formDTO, UserComputationalResource
-            computationalResource, String project, String auditInfo);
-
-    void stopSparkCluster(UserInfo userInfo, String resourceCreator, String project, String exploratoryName, String computationalName, String auditInfo);
-
-    void startSparkCluster(UserInfo userInfo, String exploratoryName, String computationalName, String project, String auditInfo);
-
-    void updateSparkClusterConfig(UserInfo userInfo, String project, String exploratoryName, String computationalName,
-                                  List<ClusterConfig> config, String auditInfo);
-
-    Optional<UserComputationalResource> getComputationalResource(String user, String project, String exploratoryName,
-                                                                 String computationalName);
-
-    List<ClusterConfig> getClusterConfig(UserInfo userInfo, String project, String exploratoryName, String computationalName);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EndpointService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EndpointService.java
deleted file mode 100644
index e30c46e..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EndpointService.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.EndpointResourcesDTO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.cloud.CloudProvider;
-
-import java.util.List;
-
-public interface EndpointService {
-	List<EndpointDTO> getEndpoints();
-
-	List<EndpointDTO> getEndpointsWithStatus(EndpointDTO.EndpointStatus status);
-
-	EndpointResourcesDTO getEndpointResources(String endpoint);
-
-	EndpointDTO get(String name);
-
-	void create(UserInfo userInfo, String resourceName, EndpointDTO endpointDTO);
-
-	void updateEndpointStatus(String name, EndpointDTO.EndpointStatus status);
-
-	void remove(UserInfo userInfo, String name);
-
-	void removeEndpointInAllProjects(UserInfo userInfo, String endpointName, List<ProjectDTO> projects);
-
-	CloudProvider checkUrl(UserInfo userInfo, String url);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EnvironmentService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EnvironmentService.java
deleted file mode 100644
index c605131..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EnvironmentService.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.UserDTO;
-import com.epam.dlab.backendapi.resources.dto.UserResourceInfo;
-
-import java.util.List;
-
-public interface EnvironmentService {
-	List<UserDTO> getUsers();
-
-	List<UserResourceInfo> getAllEnv(UserInfo user);
-
-	void stopAll();
-
-	void stopEnvironmentWithServiceAccount(String user);
-
-	void stopProjectEnvironment(String project);
-
-	void stopExploratory(UserInfo userInfo, String user, String project, String exploratoryName);
-
-	void stopComputational(UserInfo userInfo, String user, String project, String exploratoryName, String computationalName);
-
-	void terminateExploratory(UserInfo userInfo, String user, String project, String exploratoryName);
-
-	void terminateComputational(UserInfo userInfo, String user, String project, String exploratoryName, String computationalName);
-}
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
deleted file mode 100644
index af49313..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ExploratoryService.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.resources.dto.ExploratoryCreatePopUp;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.model.exploratory.Exploratory;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-public interface ExploratoryService {
-
-    String start(UserInfo userInfo, String exploratoryName, String project, String auditInfo);
-
-    String stop(UserInfo userInfo, String resourceCreator, String project, String exploratoryName, String auditInfo);
-
-    String terminate(UserInfo userInfo, String resourceCreator, String project, String exploratoryName, String auditInfo);
-
-    String create(UserInfo userInfo, Exploratory exploratory, String project, String exploratoryName);
-
-    void updateProjectExploratoryStatuses(UserInfo userInfo, String project, String endpoint, UserInstanceStatus status);
-
-    void updateProjectExploratoryStatuses(String project, String endpoint, UserInstanceStatus status);
-
-    void updateClusterConfig(UserInfo userInfo, String project, String exploratoryName, List<ClusterConfig> config);
-
-    Optional<UserInstanceDTO> getUserInstance(String user, String project, String exploratoryName);
-
-    Optional<UserInstanceDTO> getUserInstance(String user, String project, String exploratoryName, boolean includeCompResources);
-
-    List<UserInstanceDTO> findAll();
-
-    List<UserInstanceDTO> findAll(Set<ProjectDTO> projects);
-
-    List<ClusterConfig> getClusterConfig(UserInfo user, String project, String exploratoryName);
-
-    ExploratoryCreatePopUp getUserInstances(UserInfo user);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ExternalLibraryService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ExternalLibraryService.java
deleted file mode 100644
index 2ecd82a..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ExternalLibraryService.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.resources.dto.LibraryDTO;
-
-@FunctionalInterface
-public interface ExternalLibraryService {
-
-	LibraryDTO getLibrary(String groupId, String artifactId, String version);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/GitCredentialService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/GitCredentialService.java
deleted file mode 100644
index 2df8ee4..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/GitCredentialService.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsDTO;
-
-public interface GitCredentialService {
-	void updateGitCredentials(UserInfo userInfo, ExploratoryGitCredsDTO dto);
-
-	ExploratoryGitCredsDTO getGitCredentials(String user);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/GuacamoleService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/GuacamoleService.java
deleted file mode 100644
index 68df4b1..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/GuacamoleService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import org.apache.guacamole.net.GuacamoleTunnel;
-
-@FunctionalInterface
-public interface GuacamoleService {
-
-	GuacamoleTunnel getTunnel(UserInfo userInfo, String host, String endpoint);
-
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ImageExploratoryService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ImageExploratoryService.java
deleted file mode 100644
index 2b8e4c3..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ImageExploratoryService.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.ImageInfoRecord;
-import com.epam.dlab.model.exploratory.Image;
-
-import java.util.List;
-
-public interface ImageExploratoryService {
-
-    String createImage(UserInfo user, String project, String exploratoryName, String imageName, String imageDescription, String info);
-
-    void finishImageCreate(Image image, String exploratoryName, String newNotebookIp);
-
-    List<ImageInfoRecord> getNotFailedImages(String user, String dockerImage, String project, String endpoint);
-
-    ImageInfoRecord getImage(String user, String name, String project, String endpoint);
-
-    List<ImageInfoRecord> getImagesForProject(String project);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InactivityService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InactivityService.java
deleted file mode 100644
index 038a7b6..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InactivityService.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.auth.UserInfo;
-
-import java.time.LocalDateTime;
-
-public interface InactivityService {
-
-    void updateRunningResourcesLastActivity();
-
-    void updateLastActivityForExploratory(UserInfo userInfo, String exploratoryName, LocalDateTime lastActivity);
-
-    void updateLastActivityForComputational(UserInfo userInfo, String project, String exploratoryName,
-                                            String computationalName, LocalDateTime lastActivity);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureInfoService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureInfoService.java
deleted file mode 100644
index b8fe079..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureInfoService.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.HealthStatusPageDTO;
-import com.epam.dlab.backendapi.resources.dto.ProjectInfrastructureInfo;
-import com.epam.dlab.dto.InfrastructureMetaInfoDTO;
-
-import java.util.List;
-
-public interface InfrastructureInfoService {
-	List<ProjectInfrastructureInfo> getUserResources(UserInfo user);
-
-	HealthStatusPageDTO getHeathStatus(UserInfo user);
-
-	InfrastructureMetaInfoDTO getInfrastructureMetaInfo();
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureTemplateService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureTemplateService.java
deleted file mode 100644
index c5219ee..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureTemplateService.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.dto.base.computational.FullComputationalTemplate;
-import com.epam.dlab.dto.imagemetadata.ExploratoryMetadataDTO;
-
-import java.util.List;
-
-public interface InfrastructureTemplateService {
-	List<ExploratoryMetadataDTO> getExploratoryTemplates(UserInfo user, String project, String endpoint);
-
-	List<FullComputationalTemplate> getComputationalTemplates(UserInfo user, String project, String endpoint);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/KeycloakService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/KeycloakService.java
deleted file mode 100644
index b62de5f..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/KeycloakService.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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 org.keycloak.representations.AccessTokenResponse;
-
-public interface KeycloakService {
-	AccessTokenResponse getToken(String code);
-
-	AccessTokenResponse refreshToken(String refreshToken);
-
-	AccessTokenResponse generateAccessToken(String refreshToken);
-
-	AccessTokenResponse generateServiceAccountToken();
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/KeycloakServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/KeycloakServiceImpl.java
deleted file mode 100644
index 871839d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/KeycloakServiceImpl.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.SecurityDAO;
-import com.epam.dlab.backendapi.util.KeycloakUtil;
-import com.epam.dlab.exceptions.DlabException;
-import com.google.inject.Inject;
-import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
-import lombok.extern.slf4j.Slf4j;
-import org.glassfish.jersey.internal.util.Base64;
-import org.keycloak.representations.AccessTokenResponse;
-
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.Form;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.Response;
-
-@Slf4j
-public class KeycloakServiceImpl implements KeycloakService {
-
-	private static final String URI = "/realms/%s/protocol/openid-connect/token";
-	private static final String GRANT_TYPE = "grant_type";
-	private final Client httpClient;
-	private final KeycloakConfiguration conf;
-	private final SecurityDAO securityDAO;
-	private final String redirectUri;
-
-	@Inject
-	public KeycloakServiceImpl(Client httpClient, SelfServiceApplicationConfiguration conf, SecurityDAO securityDAO) {
-		this.httpClient = httpClient;
-		this.conf = conf.getKeycloakConfiguration();
-		this.securityDAO = securityDAO;
-		this.redirectUri = conf.getKeycloakConfiguration().getRedirectUri();
-	}
-
-	@Override
-	public AccessTokenResponse getToken(String code) {
-		return requestToken(accessTokenRequestForm(code));
-	}
-
-	@Override
-	public AccessTokenResponse refreshToken(String refreshToken) {
-		return requestToken(refreshTokenRequestForm(refreshToken));
-	}
-
-	@Override
-	public AccessTokenResponse generateAccessToken(String refreshToken) {
-		AccessTokenResponse tokenResponse = refreshToken(refreshToken);
-		final String username = KeycloakUtil.parseToken(tokenResponse.getToken()).getPreferredUsername();
-		securityDAO.updateUser(username, tokenResponse);
-		return tokenResponse;
-	}
-
-	@Override
-	public AccessTokenResponse generateServiceAccountToken() {
-		return requestToken(serviceAccountRequestForm());
-	}
-
-	private AccessTokenResponse requestToken(Form requestForm) {
-		final String credentials = Base64.encodeAsString(String.join(":", conf.getResource(),
-				String.valueOf(conf.getCredentials().get("secret"))));
-		final Response response =
-				httpClient.target(conf.getAuthServerUrl() + String.format(URI, conf.getRealm())).request()
-						.header(HttpHeaders.AUTHORIZATION, "Basic " + credentials)
-						.post(Entity.form(requestForm));
-		if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) {
-
-			log.error("Error getting token:code {}, body {}", response.getStatus(), response.readEntity(String.class));
-			throw new DlabException("can not get token");
-		}
-		return response.readEntity(AccessTokenResponse.class);
-	}
-
-	private Form accessTokenRequestForm(String code) {
-		return new Form()
-				.param(GRANT_TYPE, "authorization_code")
-				.param("code", code)
-				.param("redirect_uri", redirectUri);
-	}
-
-	private Form refreshTokenRequestForm(String refreshToken) {
-		return new Form()
-				.param(GRANT_TYPE, "refresh_token")
-				.param("refresh_token", refreshToken);
-	}
-
-	private Form serviceAccountRequestForm() {
-		return new Form()
-				.param(GRANT_TYPE, "client_credentials");
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/LibraryService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/LibraryService.java
deleted file mode 100644
index ba689f5..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/LibraryService.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.LibInfoRecord;
-import com.epam.dlab.dto.exploratory.LibInstallDTO;
-import org.bson.Document;
-
-import java.util.List;
-
-public interface LibraryService {
-	List<Document> getLibs(String user, String project, String exploratoryName, String computationalName);
-
-	List<LibInfoRecord> getLibInfo(String user, String project, String exploratoryName);
-
-	String installComputationalLibs(UserInfo userInfo, String project, String exploratoryName, String computationalName,
-	                                List<LibInstallDTO> libs, String auditInfo);
-
-	String installExploratoryLibs(UserInfo userInfo, String project, String exploratoryName, List<LibInstallDTO> libs, String auditInfo);
-
-	List<String> getExploratoryLibGroups(UserInfo userInfo, String projectName, String exploratoryName);
-
-	List<String> getComputeLibGroups();
-}
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
deleted file mode 100644
index 2656e48..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.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;
-
-public interface ProjectService {
-	List<ProjectDTO> getProjects();
-
-	List<ProjectDTO> getProjects(UserInfo user);
-
-	List<ProjectDTO> getUserProjects(UserInfo userInfo, boolean active);
-
-	List<ProjectDTO> getProjectsByEndpoint(String endpointName);
-
-	void create(UserInfo userInfo, ProjectDTO projectDTO, String resourceName);
-
-	ProjectDTO get(String name);
-
-	void terminateEndpoint(UserInfo userInfo, String endpoint, String name);
-
-	void terminateEndpoint(UserInfo userInfo, List<String> endpoints, String name);
-
-	void start(UserInfo userInfo, String endpoint, String name);
-
-	void start(UserInfo userInfo, List<String> endpoints, String name);
-
-	void stop(UserInfo userInfo, String endpoint, String name, String auditInfo);
-
-	void stopWithResources(UserInfo userInfo, List<String> endpoints, String projectName);
-
-	void update(UserInfo userInfo, UpdateProjectDTO projectDTO, String projectName);
-
-	void updateBudget(UserInfo userInfo, List<UpdateProjectBudgetDTO> projects);
-
-	boolean isAnyProjectAssigned(UserInfo userInfo);
-
-	boolean checkExploratoriesAndComputationalProgress(String projectName, List<String> endpoints);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ReuploadKeyService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ReuploadKeyService.java
deleted file mode 100644
index 25d2cc0..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ReuploadKeyService.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.dto.reuploadkey.ReuploadKeyStatusDTO;
-
-@FunctionalInterface
-public interface ReuploadKeyService {
-
-	void updateResourceData(ReuploadKeyStatusDTO dto);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/SchedulerJobService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/SchedulerJobService.java
deleted file mode 100644
index 7ac7f94..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/SchedulerJobService.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.dto.SchedulerJobDTO;
-import com.epam.dlab.model.scheduler.SchedulerJobData;
-
-import java.util.List;
-
-public interface SchedulerJobService {
-    /**
-     * Pulls out scheduler job data for user <code>user<code/> and his exploratory <code>exploratoryName<code/>
-     *
-     * @param user            user's name
-     * @param project         project name
-     * @param exploratoryName name of exploratory resource
-     * @return dto object
-     */
-    SchedulerJobDTO fetchSchedulerJobForUserAndExploratory(String user, String project, String exploratoryName);
-
-    /**
-     * Pulls out scheduler job data for computational resource <code>computationalName<code/> affiliated with
-     * user <code>user<code/> and his exploratory <code>exploratoryName<code/>
-     *
-     * @param user              user's name
-     * @param project           project name
-     * @param exploratoryName   name of exploratory resource
-     * @param computationalName name of computational resource
-     * @return dto object
-     */
-    SchedulerJobDTO fetchSchedulerJobForComputationalResource(String user, String project, String exploratoryName,
-                                                              String computationalName);
-
-    /**
-     * Updates scheduler job data for user <code>user<code/> and his exploratory <code>exploratoryName<code/>
-     *
-     * @param user            user's name
-     * @param project         project name
-     * @param exploratoryName name of exploratory resource
-     * @param dto             scheduler job data
-     */
-    void updateExploratorySchedulerData(UserInfo user, String project, String exploratoryName, SchedulerJobDTO dto);
-
-    /**
-     * Updates scheduler job data for computational resource <code>computationalName<code/> affiliated with
-     * user <code>user<code/> and his exploratory <code>exploratoryName<code/>
-     *
-     * @param user              user's name
-     * @param project           project name
-     * @param exploratoryName   name of exploratory resource
-     * @param computationalName name of computational resource
-     * @param dto               scheduler job data
-     */
-    void updateComputationalSchedulerData(UserInfo user, String project, String exploratoryName,
-                                          String computationalName, SchedulerJobDTO dto);
-
-    void stopComputationalByScheduler();
-
-    void stopExploratoryByScheduler();
-
-    void startExploratoryByScheduler();
-
-    void startComputationalByScheduler();
-
-    void terminateExploratoryByScheduler();
-
-	void terminateComputationalByScheduler();
-
-	void removeScheduler(String user, String exploratoryName);
-
-	void removeScheduler(String user, String exploratoryName, String computationalName);
-
-	List<SchedulerJobData> getActiveSchedulers(String user, long timeOffset);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/SecurityService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/SecurityService.java
deleted file mode 100644
index c30a670..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/SecurityService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.auth.UserInfo;
-
-public interface SecurityService {
-	UserInfo getUserInfo(String code);
-
-	UserInfo getUserInfoOffline(String username);
-
-	UserInfo getServiceAccountInfo(String username);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/SecurityServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/SecurityServiceImpl.java
deleted file mode 100644
index 73dc677..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/SecurityServiceImpl.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.SecurityDAO;
-import com.epam.dlab.backendapi.domain.AuditActionEnum;
-import com.epam.dlab.backendapi.domain.AuditDTO;
-import com.epam.dlab.backendapi.util.KeycloakUtil;
-import com.epam.dlab.exceptions.DlabException;
-import com.google.inject.Inject;
-import org.keycloak.representations.AccessTokenResponse;
-
-public class SecurityServiceImpl implements SecurityService {
-	private final KeycloakService keycloakService;
-	private final SecurityDAO securityDAO;
-	private final AuditService auditService;
-
-	@Inject
-	public SecurityServiceImpl(KeycloakService keycloakService, SecurityDAO securityDAO, AuditService auditService) {
-		this.keycloakService = keycloakService;
-		this.securityDAO = securityDAO;
-		this.auditService = auditService;
-	}
-
-	@Override
-	public UserInfo getUserInfo(String code) {
-		final AccessTokenResponse token = keycloakService.getToken(code);
-		final String username = KeycloakUtil.parseToken(token.getToken()).getPreferredUsername();
-		securityDAO.saveUser(username, token);
-		UserInfo userInfo = new UserInfo(username, token.getToken());
-		userInfo.setRefreshToken(token.getRefreshToken());
-		saveLogInAudit(username);
-		return userInfo;
-	}
-
-	@Override
-	public UserInfo getUserInfoOffline(String username) {
-		return securityDAO.getTokenResponse(username)
-				.map(AccessTokenResponse::getRefreshToken)
-				.map(keycloakService::refreshToken)
-				.map(accessTokenResponse -> new UserInfo(KeycloakUtil.parseToken(accessTokenResponse.getToken()).getPreferredUsername(),
-						accessTokenResponse.getToken()))
-				.orElseThrow(() -> new DlabException("Can not find token for user " + username));
-	}
-
-	@Override
-	public UserInfo getServiceAccountInfo(String username) {
-		AccessTokenResponse accessTokenResponse = keycloakService.generateServiceAccountToken();
-		return new UserInfo(username, accessTokenResponse.getToken());
-	}
-
-	private void saveLogInAudit(String username) {
-		AuditDTO auditDTO = AuditDTO.builder()
-				.user(username)
-				.action(AuditActionEnum.LOG_IN)
-				.build();
-		auditService.save(auditDTO);
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/SystemInfoService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/SystemInfoService.java
deleted file mode 100644
index 6e6a576..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/SystemInfoService.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.resources.dto.SystemInfoDto;
-
-@FunctionalInterface
-public interface SystemInfoService {
-
-	SystemInfoDto getSystemInfo();
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/TagService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/TagService.java
deleted file mode 100644
index b5451ca..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/TagService.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.auth.UserInfo;
-
-import java.util.Map;
-
-@FunctionalInterface
-public interface TagService {
-	Map<String, String> getResourceTags(UserInfo userInfo, String endpoint, String project, String customTag);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/TagServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/TagServiceImpl.java
deleted file mode 100644
index 5238a2f..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/TagServiceImpl.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.google.inject.Singleton;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-
-@Singleton
-public class TagServiceImpl implements TagService {
-
-	@Override
-	public Map<String, String> getResourceTags(UserInfo userInfo, String endpoint, String project, String customTag) {
-		Map<String, String> tags = new HashMap<>();
-		tags.put("user_tag", userInfo.getName());
-		tags.put("endpoint_tag", endpoint);
-		tags.put("project_tag", project);
-		Optional.ofNullable(customTag).ifPresent(t -> tags.put("custom_tag", t));
-		return tags;
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserGroupService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserGroupService.java
deleted file mode 100644
index 810ff41..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserGroupService.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.UserGroupDto;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-public interface UserGroupService {
-
-    void createGroup(UserInfo userInfo, String group, Set<String> roleIds, Set<String> users);
-
-    void updateGroup(UserInfo user, String group, Map<String, String> roles, Set<String> users);
-
-    void removeGroup(UserInfo userInfo, String groupId);
-
-    List<UserGroupDto> getAggregatedRolesByGroup(UserInfo user);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserRoleService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserRoleService.java
deleted file mode 100644
index 0b22b1d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserRoleService.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.resources.dto.UserRoleDto;
-
-import java.util.List;
-
-public interface UserRoleService {
-
-	List<UserRoleDto> getUserRoles();
-
-	void createRole(UserRoleDto dto);
-
-	void updateRole(UserRoleDto dto);
-
-	void removeRole(String roleId);
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserRoleServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserRoleServiceImpl.java
deleted file mode 100644
index 5f3f6a3..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserRoleServiceImpl.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.dao.UserRoleDAO;
-import com.epam.dlab.backendapi.resources.dto.UserRoleDto;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-@Singleton
-public class UserRoleServiceImpl implements UserRoleService {
-	private static final String ROLE_NOT_FOUND_MSG = "Any of role : %s were not found";
-
-	@Inject
-	private UserRoleDAO userRoleDao;
-
-	@Override
-	public List<UserRoleDto> getUserRoles() {
-		return userRoleDao.findAll();
-	}
-
-	@Override
-	public void createRole(UserRoleDto dto) {
-		userRoleDao.insert(dto);
-	}
-
-	@Override
-	public void updateRole(UserRoleDto dto) {
-		checkAnyRoleFound(Collections.singleton(dto.getId()), userRoleDao.update(dto));
-	}
-
-	@Override
-	public void removeRole(String roleId) {
-		userRoleDao.remove(roleId);
-	}
-
-	private void checkAnyRoleFound(Set<String> roleIds, boolean anyRoleFound) {
-		if (!anyRoleFound) {
-			throw new ResourceNotFoundException(String.format(ROLE_NOT_FOUND_MSG, roleIds));
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserSettingService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserSettingService.java
deleted file mode 100644
index 5aae379..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserSettingService.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.UserDTO;
-
-import java.util.List;
-
-public interface UserSettingService {
-
-	void saveUISettings(UserInfo userInfo, String settings);
-
-	String getUISettings(UserInfo userInfo);
-
-	void updateUsersBudget(List<UserDTO> budgets);
-
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserSettingServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserSettingServiceImpl.java
deleted file mode 100644
index 296cd17..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/UserSettingServiceImpl.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.UserSettingsDAO;
-import com.epam.dlab.backendapi.resources.dto.UserDTO;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-import java.util.List;
-
-@Singleton
-public class UserSettingServiceImpl implements UserSettingService {
-	@Inject
-	private UserSettingsDAO settingsDAO;
-
-	@Override
-	public void saveUISettings(UserInfo userInfo, String settings) {
-		settingsDAO.setUISettings(userInfo, settings);
-	}
-
-	@Override
-	public String getUISettings(UserInfo userInfo) {
-		return settingsDAO.getUISettings(userInfo);
-	}
-
-	@Override
-	public void updateUsersBudget(List<UserDTO> budgets) {
-		budgets.forEach(settingsDAO::updateBudget);
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AccessKeyServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AccessKeyServiceImpl.java
deleted file mode 100644
index 11c8ef4..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AccessKeyServiceImpl.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.resources.dto.KeysDTO;
-import com.epam.dlab.backendapi.service.AccessKeyService;
-import com.epam.dlab.exceptions.DlabException;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.JSchException;
-import com.jcraft.jsch.KeyPair;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-@Singleton
-@Slf4j
-public class AccessKeyServiceImpl implements AccessKeyService {
-	@Inject
-	private SelfServiceApplicationConfiguration configuration;
-
-
-	@Override
-	public KeysDTO generateKeys(UserInfo userInfo) {
-		log.debug("Generating new key pair for user {}", userInfo.getName());
-		try (ByteArrayOutputStream publicKeyOut = new ByteArrayOutputStream();
-			 ByteArrayOutputStream privateKeyOut = new ByteArrayOutputStream()) {
-			KeyPair pair = KeyPair.genKeyPair(new JSch(), KeyPair.RSA, configuration.getPrivateKeySize());
-			pair.writePublicKey(publicKeyOut, userInfo.getName());
-			pair.writePrivateKey(privateKeyOut);
-			return new KeysDTO(new String(publicKeyOut.toByteArray()),
-					new String(privateKeyOut.toByteArray()), userInfo.getName());
-		} catch (JSchException | IOException e) {
-			log.error("Can not generate private/public key pair due to: {}", e.getMessage());
-			throw new DlabException("Can not generate private/public key pair due to: " + e.getMessage(), e);
-		}
-	}
-}
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
deleted file mode 100644
index 94d6a82..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.domain.AuditDTO;
-import com.epam.dlab.backendapi.domain.AuditPaginationDTO;
-import com.epam.dlab.backendapi.service.AuditService;
-import com.google.inject.Inject;
-
-import java.util.List;
-
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.FOLLOW_LINK;
-
-public class AuditServiceImpl implements AuditService {
-    private final AuditDAO auditDAO;
-
-    @Inject
-    public AuditServiceImpl(AuditDAO auditDAO) {
-        this.auditDAO = auditDAO;
-    }
-
-    @Override
-    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(FOLLOW_LINK)
-                .type(audit.getType())
-                .info(audit.getInfo())
-                .build();
-        auditDAO.save(auditDTO);
-    }
-
-    @Override
-    public List<AuditPaginationDTO> getAudit(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes,
-                                             String dateStart, String dateEnd, int pageNumber, int pageSize) {
-        return auditDAO.getAudit(users, projects, resourceNames, resourceTypes, dateStart, dateEnd, pageNumber, pageSize);
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BackupServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BackupServiceImpl.java
deleted file mode 100644
index 1a93470..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BackupServiceImpl.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.BackupDAO;
-import com.epam.dlab.backendapi.resources.dto.BackupInfoRecord;
-import com.epam.dlab.backendapi.service.BackupService;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.backup.EnvBackupDTO;
-import com.epam.dlab.dto.backup.EnvBackupStatus;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.BackupAPI;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-
-import java.util.List;
-
-@Singleton
-public class BackupServiceImpl implements BackupService {
-
-	@Inject
-	@Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
-	private RESTService provisioningService;
-
-	@Inject
-	private BackupDAO backupDao;
-
-	@Override
-	public String createBackup(EnvBackupDTO dto, UserInfo user) {
-		updateStatus(dto, user.getName(), EnvBackupStatus.CREATING);
-		return provisioningService.post(BackupAPI.BACKUP, user.getAccessToken(), dto, String.class);
-	}
-
-	@Override
-	public void updateStatus(EnvBackupDTO dto, String user, EnvBackupStatus status) {
-		backupDao.createOrUpdate(dto, user, status);
-	}
-
-	@Override
-	public List<BackupInfoRecord> getBackups(String userName) {
-		return backupDao.getBackups(userName);
-	}
-
-	@Override
-	public BackupInfoRecord getBackup(String userName, String id) {
-		return backupDao.getBackup(userName, id).orElseThrow(() -> new ResourceNotFoundException(
-				String.format("Backup with id %s was not found for user %s", id, userName)));
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BillingServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BillingServiceImpl.java
deleted file mode 100644
index d5675f0..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BillingServiceImpl.java
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.BillingDAO;
-import com.epam.dlab.backendapi.dao.ImageExploratoryDAO;
-import com.epam.dlab.backendapi.dao.ProjectDAO;
-import com.epam.dlab.backendapi.domain.BillingReport;
-import com.epam.dlab.backendapi.domain.BillingReportLine;
-import com.epam.dlab.backendapi.domain.BudgetDTO;
-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.resources.dto.BillingFilter;
-import com.epam.dlab.backendapi.resources.dto.QuotaUsageDTO;
-import com.epam.dlab.backendapi.roles.RoleType;
-import com.epam.dlab.backendapi.roles.UserRoles;
-import com.epam.dlab.backendapi.service.BillingService;
-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.util.BillingUtils;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.billing.BillingData;
-import com.epam.dlab.dto.billing.BillingResourceType;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.common.collect.Lists;
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.http.client.utils.URIBuilder;
-
-import javax.ws.rs.core.GenericType;
-import java.math.BigDecimal;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.time.LocalDate;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-@Slf4j
-public class BillingServiceImpl implements BillingService {
-    private static final String BILLING_PATH = "/api/billing";
-    private static final String USAGE_DATE_FORMAT = "yyyy-MM";
-
-    private final ProjectService projectService;
-    private final ProjectDAO projectDAO;
-    private final EndpointService endpointService;
-    private final ExploratoryService exploratoryService;
-    private final SelfServiceApplicationConfiguration configuration;
-    private final RESTService provisioningService;
-    private final ImageExploratoryDAO imageExploratoryDao;
-    private final BillingDAO billingDAO;
-
-    @Inject
-    public BillingServiceImpl(ProjectService projectService, ProjectDAO projectDAO, EndpointService endpointService,
-                              ExploratoryService exploratoryService, SelfServiceApplicationConfiguration configuration,
-                              @Named(ServiceConsts.BILLING_SERVICE_NAME) RESTService provisioningService, ImageExploratoryDAO imageExploratoryDao,
-                              BillingDAO billingDAO) {
-        this.projectService = projectService;
-        this.projectDAO = projectDAO;
-        this.endpointService = endpointService;
-        this.exploratoryService = exploratoryService;
-        this.configuration = configuration;
-        this.provisioningService = provisioningService;
-        this.imageExploratoryDao = imageExploratoryDao;
-        this.billingDAO = billingDAO;
-    }
-
-    @Override
-    public BillingReport getBillingReport(UserInfo user, BillingFilter filter) {
-        setUserFilter(user, filter);
-        List<BillingReportLine> billingReportLines = billingDAO.aggregateBillingData(filter)
-                .stream()
-                .peek(this::appendStatuses)
-                .filter(bd -> CollectionUtils.isEmpty(filter.getStatuses()) || filter.getStatuses().contains(bd.getStatus()))
-                .collect(Collectors.toList());
-        final LocalDate min = billingReportLines.stream().min(Comparator.comparing(BillingReportLine::getUsageDateFrom)).map(BillingReportLine::getUsageDateFrom).orElse(null);
-        final LocalDate max = billingReportLines.stream().max(Comparator.comparing(BillingReportLine::getUsageDateTo)).map(BillingReportLine::getUsageDateTo).orElse(null);
-        final double sum = billingReportLines.stream().mapToDouble(BillingReportLine::getCost).sum();
-        final String currency = billingReportLines.stream().map(BillingReportLine::getCurrency).distinct().count() == 1 ? billingReportLines.get(0).getCurrency() : null;
-        return BillingReport.builder()
-                .name("Billing report")
-                .sbn(configuration.getServiceBaseName())
-		        .reportLines(billingReportLines)
-		        .usageDateFrom(min)
-		        .usageDateTo(max)
-		        .totalCost(BigDecimal.valueOf(sum).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue())
-                .currency(currency)
-                .isReportHeaderCompletable(hasUserBillingRole(user))
-                .build();
-    }
-
-    @Override
-    public String downloadReport(UserInfo user, BillingFilter filter) {
-        BillingReport report = getBillingReport(user, filter);
-        boolean isReportComplete = report.isReportHeaderCompletable();
-        StringBuilder reportHead = new StringBuilder(BillingUtils.getFirstLine(report.getSbn(), report.getUsageDateFrom(), report.getUsageDateTo()));
-        String stringOfAdjustedHeader = BillingUtils.getHeader(isReportComplete);
-        reportHead.append(stringOfAdjustedHeader);
-        report.getReportLines().forEach(r -> reportHead.append(BillingUtils.printLine(r, isReportComplete)));
-        reportHead.append(BillingUtils.getTotal(report.getTotalCost(), report.getCurrency(), stringOfAdjustedHeader));
-        return reportHead.toString();
-    }
-
-    @Override
-    public BillingReport getExploratoryBillingData(String project, String endpoint, String exploratoryName, List<String> compNames) {
-        List<String> resourceNames = new ArrayList<>(compNames);
-        resourceNames.add(exploratoryName);
-        List<BillingReportLine> billingReportLines = billingDAO.findBillingData(project, endpoint, resourceNames);
-        final double sum = billingReportLines.stream().mapToDouble(BillingReportLine::getCost).sum();
-        List<BillingReportLine> billingData = billingReportLines
-                .stream()
-                .peek(bd -> bd.setCost(BigDecimal.valueOf(bd.getCost()).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()))
-                .collect(Collectors.toList());;
-        final String currency = billingData.stream().map(BillingReportLine::getCurrency).distinct().count() == 1 ? billingData.get(0).getCurrency() : null;
-        return BillingReport.builder()
-                .name(exploratoryName)
-                .reportLines(billingData)
-                .totalCost(BigDecimal.valueOf(sum).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue())
-                .currency(currency)
-                .build();
-    }
-
-    @Override
-    public void updateRemoteBillingData(UserInfo userInfo) {
-        List<EndpointDTO> endpoints = endpointService.getEndpoints();
-        if (CollectionUtils.isEmpty(endpoints)) {
-            log.error("Cannot update billing info. There are no endpoints");
-            throw new DlabException("Cannot update billing info. There are no endpoints");
-        }
-
-        Map<EndpointDTO, List<BillingData>> billingDataMap = endpoints
-                .stream()
-                .collect(Collectors.toMap(e -> e, e -> getBillingData(userInfo, e)));
-
-        billingDataMap.forEach((endpointDTO, billingData) -> {
-            log.info("Updating billing information for endpoint {}. Billing data {}", endpointDTO.getName(), billingData);
-            if (!billingData.isEmpty()) {
-                updateBillingData(endpointDTO, billingData, endpoints);
-            }
-        });
-    }
-
-    @Override
-    public QuotaUsageDTO getQuotas(UserInfo userInfo) {
-        int totalQuota = billingDAO.getBillingQuoteUsed();
-        Map<String, Integer> projectQuotas = projectService.getProjects(userInfo)
-                .stream()
-                .collect(Collectors.toMap(ProjectDTO::getName, p -> getBillingProjectQuoteUsed(p.getName())));
-        return QuotaUsageDTO.builder()
-                .totalQuotaUsed(totalQuota)
-                .projectQuotas(projectQuotas)
-                .build();
-    }
-
-    @Override
-    public boolean isProjectQuoteReached(String project) {
-        final Double projectCost = getProjectCost(project);
-        return projectDAO.getAllowedBudget(project)
-                .filter(allowedBudget -> projectCost.intValue() != 0 && allowedBudget <= projectCost)
-                .isPresent();
-    }
-
-    @Override
-    public int getBillingProjectQuoteUsed(String project) {
-        return toPercentage(() -> projectDAO.getAllowedBudget(project), getProjectCost(project));
-    }
-
-    private Double getProjectCost(String project) {
-        final boolean monthlyBudget = Optional.ofNullable(projectService.get(project).getBudget())
-                .map(BudgetDTO::isMonthlyBudget)
-                .orElse(Boolean.FALSE);
-        return monthlyBudget ? billingDAO.getMonthlyProjectCost(project, LocalDate.now()) : billingDAO.getOverallProjectCost(project);
-    }
-
-    private Map<String, BillingReportLine> getBillableResources(List<EndpointDTO> endpoints) {
-        Set<ProjectDTO> projects = new HashSet<>(projectService.getProjects());
-        final Stream<BillingReportLine> ssnBillingDataStream = BillingUtils.ssnBillingDataStream(configuration.getServiceBaseName());
-        final Stream<BillingReportLine> billableEdges = projects
-                .stream()
-                .collect(Collectors.toMap(ProjectDTO::getName, ProjectDTO::getEndpoints))
-                .entrySet()
-                .stream()
-                .flatMap(e -> projectEdges(configuration.getServiceBaseName(), e.getKey(), e.getValue()));
-        final Stream<BillingReportLine> billableSharedEndpoints = endpoints
-                .stream()
-                .flatMap(endpoint -> BillingUtils.sharedEndpointBillingDataStream(endpoint.getName(), configuration.getServiceBaseName()));
-        final Stream<BillingReportLine> billableUserInstances = exploratoryService.findAll(projects)
-                .stream()
-                .filter(userInstance -> Objects.nonNull(userInstance.getExploratoryId()))
-                .flatMap(ui -> BillingUtils.exploratoryBillingDataStream(ui, configuration.getMaxSparkInstanceCount()));
-        final Stream<BillingReportLine> customImages = projects
-                .stream()
-                .map(p -> imageExploratoryDao.getImagesForProject(p.getName()))
-                .flatMap(Collection::stream)
-                .flatMap(i -> BillingUtils.customImageBillingDataStream(i, configuration.getServiceBaseName()));
-
-        final Map<String, BillingReportLine> billableResources = Stream.of(ssnBillingDataStream, billableEdges, billableSharedEndpoints, billableUserInstances, customImages)
-                .flatMap(s -> s)
-                .collect(Collectors.toMap(BillingReportLine::getDlabId, b -> b));
-        log.debug("Billable resources are: {}", billableResources);
-
-        return billableResources;
-    }
-
-    private Stream<BillingReportLine> projectEdges(String serviceBaseName, String projectName, List<ProjectEndpointDTO> endpoints) {
-        return endpoints
-                .stream()
-                .flatMap(endpoint -> BillingUtils.edgeBillingDataStream(projectName, serviceBaseName, endpoint.getName()));
-    }
-
-    private void updateBillingData(EndpointDTO endpointDTO, List<BillingData> billingData, List<EndpointDTO> endpoints) {
-        final String endpointName = endpointDTO.getName();
-        final CloudProvider cloudProvider = endpointDTO.getCloudProvider();
-        final Map<String, BillingReportLine> billableResources = getBillableResources(endpoints);
-        final Stream<BillingReportLine> billingReportLineStream = billingData
-                .stream()
-                .peek(bd -> bd.setApplication(endpointName))
-                .map(bd -> toBillingReport(bd, getOrDefault(billableResources, bd.getTag())));
-
-        if (cloudProvider == CloudProvider.GCP) {
-            final Map<String, List<BillingReportLine>> gcpBillingData = billingReportLineStream
-                    .collect(Collectors.groupingBy(bd -> bd.getUsageDate().substring(0, USAGE_DATE_FORMAT.length())));
-            updateGcpBillingData(endpointName, gcpBillingData);
-        } else if (cloudProvider == CloudProvider.AWS) {
-            final Map<String, List<BillingReportLine>> awsBillingData = billingReportLineStream
-                    .collect(Collectors.groupingBy(BillingReportLine::getUsageDate));
-            updateAwsBillingData(endpointName, awsBillingData);
-        } else if (cloudProvider == CloudProvider.AZURE) {
-            final List<BillingReportLine> billingReportLines = billingReportLineStream
-                    .collect(Collectors.toList());
-            updateAzureBillingData(billingReportLines);
-        }
-    }
-
-    private BillingReportLine getOrDefault(Map<String, BillingReportLine> billableResources, String tag) {
-        return billableResources.getOrDefault(tag, BillingReportLine.builder().dlabId(tag).build());
-    }
-
-    private void updateGcpBillingData(String endpointName, Map<String, List<BillingReportLine>> billingData) {
-        billingData.forEach((usageDate, billingReportLines) -> {
-            billingDAO.deleteByUsageDateRegex(endpointName, usageDate);
-            billingDAO.save(billingReportLines);
-        });
-    }
-
-    private void updateAwsBillingData(String endpointName, Map<String, List<BillingReportLine>> billingData) {
-        billingData.forEach((usageDate, billingReportLines) -> {
-            billingDAO.deleteByUsageDate(endpointName, usageDate);
-            billingDAO.save(billingReportLines);
-        });
-    }
-
-    private void updateAzureBillingData(List<BillingReportLine> billingReportLines) {
-        billingDAO.save(billingReportLines);
-    }
-
-	private List<BillingData> getBillingData(UserInfo userInfo, EndpointDTO endpointDTO) {
-		try {
-			return provisioningService.get(getBillingUrl(endpointDTO.getUrl(), BILLING_PATH), userInfo.getAccessToken(),
-					new GenericType<List<BillingData>>() {
-					});
-		} catch (Exception e) {
-			log.error("Cannot retrieve billing information for {} . Reason {}.", endpointDTO.getName(), e.getMessage(), e);
-			return Collections.emptyList();
-		}
-	}
-
-    private String getBillingUrl(String endpointUrl, String path) {
-        URI uri;
-        try {
-            uri = new URI(endpointUrl);
-        } catch (URISyntaxException e) {
-            log.error("Wrong URI syntax {}", e.getMessage(), e);
-            throw new DlabException("Wrong URI syntax");
-        }
-        return new URIBuilder()
-                .setScheme(uri.getScheme())
-                .setHost(uri.getHost())
-                .setPort(8088)
-                .setPath(path)
-                .toString();
-    }
-
-    private void appendStatuses(BillingReportLine br) {
-        BillingResourceType resourceType = br.getResourceType();
-        if (BillingResourceType.EDGE == resourceType) {
-            projectService.get(br.getProject()).getEndpoints()
-                    .stream()
-                    .filter(e -> e.getName().equals(br.getResourceName()))
-                    .findAny()
-                    .ifPresent(e -> br.setStatus(e.getStatus()));
-        } else if (BillingResourceType.EXPLORATORY == resourceType) {
-            exploratoryService.getUserInstance(br.getUser(), br.getProject(), br.getResourceName())
-                    .ifPresent(ui -> br.setStatus(UserInstanceStatus.of(ui.getStatus())));
-        } else if (BillingResourceType.COMPUTATIONAL == resourceType) {
-            exploratoryService.getUserInstance(br.getUser(), br.getProject(), br.getExploratoryName(), true)
-                    .flatMap(ui -> ui.getResources()
-                            .stream()
-                            .filter(cr -> cr.getComputationalName().equals(br.getResourceName()))
-                            .findAny())
-                    .ifPresent(cr -> br.setStatus(UserInstanceStatus.of(cr.getStatus())));
-        }
-    }
-
-    /**
-     *
-     * @param userInfo user's properties for current session
-     * @return true, if user has be billing role
-     */
-    private boolean hasUserBillingRole(UserInfo userInfo) {
-        return UserRoles.checkAccess(userInfo, RoleType.PAGE, "/api/infrastructure_provision/billing", userInfo.getRoles());
-    }
-
-    private void setUserFilter(UserInfo userInfo, BillingFilter filter) {
-        if (!hasUserBillingRole(userInfo)) {
-            filter.setUsers(Lists.newArrayList(userInfo.getName()));
-        }
-    }
-
-    private BillingReportLine toBillingReport(BillingData billingData, BillingReportLine billingReportLine) {
-        return BillingReportLine.builder()
-                .application(billingData.getApplication())
-                .cost(billingData.getCost())
-                .currency(billingData.getCurrency())
-                .product(billingData.getProduct())
-                .project(billingReportLine.getProject())
-                .endpoint(billingReportLine.getEndpoint())
-                .usageDateFrom(billingData.getUsageDateFrom())
-                .usageDateTo(billingData.getUsageDateTo())
-                .usageDate(billingData.getUsageDate())
-                .usageType(billingData.getUsageType())
-                .user(billingReportLine.getUser())
-                .dlabId(billingData.getTag())
-                .resourceType(billingReportLine.getResourceType())
-                .resourceName(billingReportLine.getResourceName())
-                .shape(billingReportLine.getShape())
-                .exploratoryName(billingReportLine.getExploratoryName())
-                .build();
-    }
-
-    private Integer toPercentage(Supplier<Optional<Integer>> allowedBudget, Double totalCost) {
-        return allowedBudget.get()
-                .map(userBudget -> (totalCost * 100) / userBudget)
-                .map(Double::intValue)
-                .orElse(BigDecimal.ZERO.intValue());
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BucketServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BucketServiceImpl.java
deleted file mode 100644
index 8049857..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/BucketServiceImpl.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * 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.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.EndpointDTO;
-import com.epam.dlab.backendapi.service.BucketService;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.bucket.BucketDTO;
-import com.epam.dlab.dto.bucket.BucketDeleteDTO;
-import com.epam.dlab.dto.bucket.FolderUploadDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.io.IOUtils;
-import org.apache.http.HttpStatus;
-import org.glassfish.jersey.media.multipart.FormDataMultiPart;
-import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.DELETE;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.DOWNLOAD;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.UPLOAD;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.BUCKET;
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
-
-@Slf4j
-public class BucketServiceImpl implements BucketService {
-    private static final String BUCKET_GET_OBJECTS = "%sbucket/%s";
-    private static final String BUCKET_UPLOAD_OBJECT = "%sbucket/upload";
-    private static final String BUCKET_UPLOAD_FOLDER = "%sbucket/folder/upload";
-    private static final String BUCKET_DOWNLOAD_OBJECT = "%sbucket/%s/object/%s/download";
-    private static final String BUCKET_DELETE_OBJECT = "%sbucket/objects/delete";
-    private static final String SOMETHING_WENT_WRONG_MESSAGE = "Something went wrong. Response status is %s ";
-
-    private final EndpointService endpointService;
-    private final RESTService provisioningService;
-
-    @Inject
-    public BucketServiceImpl(EndpointService endpointService, @Named(ServiceConsts.BUCKET_SERVICE_NAME) RESTService provisioningService) {
-        this.endpointService = endpointService;
-        this.provisioningService = provisioningService;
-    }
-
-    @Override
-    public List<BucketDTO> getObjects(UserInfo userInfo, String bucket, String endpoint) {
-        try {
-            EndpointDTO endpointDTO = endpointService.get(endpoint);
-            return provisioningService.get(String.format(BUCKET_GET_OBJECTS, endpointDTO.getUrl(), bucket), userInfo.getAccessToken(), new GenericType<List<BucketDTO>>() {
-            });
-        } catch (Exception e) {
-            log.error("Cannot get objects from bucket {} for user {}, endpoint {}. Reason {}", bucket, userInfo.getName(), endpoint, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot get objects from bucket %s for user %s, endpoint %s. Reason %s", bucket, userInfo.getName(), endpoint, e.getMessage()));
-        }
-    }
-
-    @Audit(action = UPLOAD, type = BUCKET)
-    @Override
-    public void uploadObject(@User UserInfo userInfo, @ResourceName String bucket, String object, String endpoint, InputStream inputStream,String contentType, long fileSize, @Info String auditInfo) {
-        log.info("Uploading file {} for user {} to bucket {}", object, userInfo.getName(), bucket);
-        try {
-            EndpointDTO endpointDTO = endpointService.get(endpoint);
-            FormDataMultiPart formData = getFormDataMultiPart(bucket, object, inputStream, contentType, fileSize);
-            Response response = provisioningService.postForm(String.format(BUCKET_UPLOAD_OBJECT, endpointDTO.getUrl()), userInfo.getAccessToken(), formData, Response.class);
-            if (response.getStatus() != HttpStatus.SC_OK) {
-                throw new DlabException(String.format(SOMETHING_WENT_WRONG_MESSAGE, response.getStatus()));
-            }
-        } catch (Exception e) {
-	        log.error("Cannot upload object {} to bucket {} for user {}, endpoint {}. Reason {}", object, bucket, userInfo.getName(), endpoint, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot upload object %s to bucket %s for user %s, endpoint %s. Reason %s", object, bucket, userInfo.getName(), endpoint, e.getMessage()));
-        }
-        log.info("Finished uploading file {} for user {} to bucket {}", object, userInfo.getName(), bucket);
-    }
-
-    @Audit(action = UPLOAD, type = BUCKET)
-    @Override
-    public void uploadFolder(@User UserInfo userInfo, @ResourceName String bucket, String folder, String endpoint, @Info String auditInfo) {
-        log.info("Uploading folder {} for user {} to bucket {}", folder, userInfo.getName(), bucket);
-        try {
-            if (!folder.endsWith("/")) {
-                throw new DlabException("Folder doesn't end with '/'");
-            }
-            EndpointDTO endpointDTO = endpointService.get(endpoint);
-            FolderUploadDTO dto = new FolderUploadDTO(bucket, folder);
-            Response response = provisioningService.post(String.format(BUCKET_UPLOAD_FOLDER, endpointDTO.getUrl()), userInfo.getAccessToken(), dto, Response.class);
-            if (response.getStatus() != HttpStatus.SC_OK) {
-                throw new DlabException(String.format(SOMETHING_WENT_WRONG_MESSAGE, response.getStatus()));
-            }
-        } catch (Exception e) {
-	        log.error("Cannot upload folder {} to bucket {} for user {}, endpoint {}. Reason {}", folder, bucket, userInfo.getName(), endpoint, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot upload object %s to bucket %s for user %s, endpoint %s. Reason %s", folder, bucket, userInfo.getName(), endpoint, e.getMessage()));
-        }
-        log.info("Finished uploading folder {} for user {} to bucket {}", folder, userInfo.getName(), bucket);
-    }
-
-    @Audit(action = DOWNLOAD, type = BUCKET)
-    @Override
-    public void downloadObject(@User UserInfo userInfo, @ResourceName String bucket, String object, String endpoint, HttpServletResponse resp, @Info String auditInfo) {
-        log.info("Downloading file {} for user {} from bucket {}", object, userInfo.getName(), bucket);
-        EndpointDTO endpointDTO = endpointService.get(endpoint);
-        try (InputStream inputStream = provisioningService.getWithMediaTypes(String.format(BUCKET_DOWNLOAD_OBJECT, endpointDTO.getUrl(), bucket, encodeObject(object)), userInfo.getAccessToken(),
-                InputStream.class, APPLICATION_JSON, APPLICATION_OCTET_STREAM); ServletOutputStream outputStream = resp.getOutputStream()) {
-            IOUtils.copyLarge(inputStream, outputStream);
-            log.info("Finished downloading file {} for user {} from bucket {}", object, userInfo.getName(), bucket);
-        } catch (Exception e) {
-	        log.error("Cannot upload object {} from bucket {} for user {}, endpoint {}. Reason {}", object, bucket, userInfo.getName(), endpoint, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot download object %s from bucket %s for user %s, endpoint %s. Reason %s", object, bucket, userInfo.getName(), endpoint, e.getMessage()));
-        }
-    }
-
-    @Audit(action = DELETE, type = BUCKET)
-    @Override
-    public void deleteObjects(@User UserInfo userInfo, @ResourceName String bucket, List<String> objects, String endpoint, @Info String auditInfo) {
-        try {
-            EndpointDTO endpointDTO = endpointService.get(endpoint);
-            BucketDeleteDTO bucketDeleteDTO = new BucketDeleteDTO(bucket, objects);
-            Response response = provisioningService.post(String.format(BUCKET_DELETE_OBJECT, endpointDTO.getUrl()), userInfo.getAccessToken(), bucketDeleteDTO, Response.class);
-            if (response.getStatus() != HttpStatus.SC_OK) {
-                throw new DlabException(String.format(SOMETHING_WENT_WRONG_MESSAGE, response.getStatus()));
-            }
-        } catch (Exception e) {
-	        log.error("Cannot delete objects {} from bucket {} for user {}, endpoint {}. Reason {}", objects, bucket, userInfo.getName(), endpoint, e.getMessage(), e);
-            throw new DlabException(String.format("Cannot delete objects %s from bucket %s for user %s, endpoint %s. Reason %s", objects, bucket, userInfo.getName(), endpoint, e.getMessage()));
-        }
-    }
-
-    private String encodeObject(String object) throws UnsupportedEncodingException {
-        return URLEncoder.encode(object, StandardCharsets.UTF_8.toString()).replace("+", "%20");
-    }
-
-    private FormDataMultiPart getFormDataMultiPart(String bucket, String object, InputStream inputStream, String contentType, long fileSize) {
-        StreamDataBodyPart filePart = new StreamDataBodyPart("file", inputStream, object, MediaType.valueOf(contentType));
-        FormDataMultiPart formData = new FormDataMultiPart();
-        formData.field("bucket", bucket);
-        formData.field("object", object);
-        formData.field("file-size", String.valueOf(fileSize));
-        formData.bodyPart(filePart);
-        return formData;
-    }
-}
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
deleted file mode 100644
index 28bd09c..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * 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.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;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.resources.dto.ComputationalCreateFormDTO;
-import com.epam.dlab.backendapi.resources.dto.ComputationalTemplatesDTO;
-import com.epam.dlab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
-import com.epam.dlab.backendapi.service.ComputationalService;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.InfrastructureTemplateService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.backendapi.service.TagService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.constants.ServiceConsts;
-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.base.DataEngineType;
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.epam.dlab.dto.base.computational.FullComputationalTemplate;
-import com.epam.dlab.dto.computational.ComputationalClusterConfigDTO;
-import com.epam.dlab.dto.computational.ComputationalStatusDTO;
-import com.epam.dlab.dto.computational.ComputationalTerminateDTO;
-import com.epam.dlab.dto.computational.SparkStandaloneClusterResource;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.ComputationalAPI;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Collection;
-import java.util.EnumMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.CREATE;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.RECONFIGURE;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.START;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.STOP;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.TERMINATE;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.COMPUTE;
-import static com.epam.dlab.dto.UserInstanceStatus.CREATING;
-import static com.epam.dlab.dto.UserInstanceStatus.FAILED;
-import static com.epam.dlab.dto.UserInstanceStatus.RECONFIGURING;
-import static com.epam.dlab.dto.UserInstanceStatus.STARTING;
-import static com.epam.dlab.dto.UserInstanceStatus.STOPPING;
-import static com.epam.dlab.dto.UserInstanceStatus.TERMINATING;
-import static com.epam.dlab.dto.base.DataEngineType.CLOUD_SERVICE;
-import static com.epam.dlab.dto.base.DataEngineType.SPARK_STANDALONE;
-import static com.epam.dlab.rest.contracts.ComputationalAPI.COMPUTATIONAL_CREATE_CLOUD_SPECIFIC;
-
-@Singleton
-@Slf4j
-public class ComputationalServiceImpl implements ComputationalService {
-
-	private static final String COULD_NOT_UPDATE_THE_STATUS_MSG_FORMAT = "Could not update the status of " +
-			"computational resource {} for user {}";
-	private static final EnumMap<DataEngineType, String> DATA_ENGINE_TYPE_TERMINATE_URLS;
-	private static final String DATAENGINE_NOT_PRESENT_FORMAT = "There is no %s dataengine %s for exploratory %s";
-	private static final String RUNNING_COMP_RES_NOT_FOUND = "Running computational resource with " +
-			"name %s for exploratory %s not found";
-
-	static {
-		DATA_ENGINE_TYPE_TERMINATE_URLS = new EnumMap<>(DataEngineType.class);
-		DATA_ENGINE_TYPE_TERMINATE_URLS.put(SPARK_STANDALONE, ComputationalAPI.COMPUTATIONAL_TERMINATE_SPARK);
-		DATA_ENGINE_TYPE_TERMINATE_URLS.put(CLOUD_SERVICE, ComputationalAPI.COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC);
-	}
-
-	private final ProjectService projectService;
-	private final ExploratoryDAO exploratoryDAO;
-	private final ComputationalDAO computationalDAO;
-	private final RESTService provisioningService;
-	private final RequestBuilder requestBuilder;
-	private final RequestId requestId;
-	private final TagService tagService;
-	private final EndpointService endpointService;
-	private final InfrastructureTemplateService templateService;
-
-	@Inject
-	public ComputationalServiceImpl(ProjectService projectService, ExploratoryDAO exploratoryDAO, ComputationalDAO computationalDAO,
-									@Named(ServiceConsts.PROVISIONING_SERVICE_NAME) RESTService provisioningService,
-									RequestBuilder requestBuilder, RequestId requestId, TagService tagService,
-									EndpointService endpointService, InfrastructureTemplateService templateService) {
-		this.projectService = projectService;
-		this.exploratoryDAO = exploratoryDAO;
-		this.computationalDAO = computationalDAO;
-		this.provisioningService = provisioningService;
-		this.requestBuilder = requestBuilder;
-		this.requestId = requestId;
-		this.tagService = tagService;
-		this.endpointService = endpointService;
-		this.templateService = templateService;
-	}
-
-
-	@Override
-	public ComputationalTemplatesDTO getComputationalNamesAndTemplates(UserInfo user, String project, String endpoint) {
-		List<FullComputationalTemplate> computationalTemplates = templateService.getComputationalTemplates(user, project, endpoint);
-		List<UserInstanceDTO> userInstances = exploratoryDAO.fetchExploratoryFieldsForProjectWithComp(project);
-
-		List<String> projectComputations = userInstances
-				.stream()
-				.map(UserInstanceDTO::getResources)
-				.flatMap(Collection::stream)
-				.map(UserComputationalResource::getComputationalName)
-				.collect(Collectors.toList());
-		List<String> userComputations = userInstances
-				.stream()
-				.filter(instance -> instance.getUser().equalsIgnoreCase(user.getName()))
-				.map(UserInstanceDTO::getResources)
-				.flatMap(Collection::stream)
-				.map(UserComputationalResource::getComputationalName)
-				.collect(Collectors.toList());
-
-		return new ComputationalTemplatesDTO(computationalTemplates, userComputations, projectComputations);
-	}
-
-	@BudgetLimited
-	@Audit(action = CREATE, type = COMPUTE)
-	@Override
-	public boolean createSparkCluster(@User UserInfo userInfo, @ResourceName String resourceName, SparkStandaloneClusterCreateForm form, @Project String project,
-                                      @Info String auditInfo) {
-        final ProjectDTO projectDTO = projectService.get(project);
-        final UserInstanceDTO instance =
-                exploratoryDAO.fetchExploratoryFields(userInfo.getName(), project, form.getNotebookName());
-        final SparkStandaloneClusterResource compResource = createInitialComputationalResource(form);
-        compResource.setTags(tagService.getResourceTags(userInfo, instance.getEndpoint(), project,
-                form.getCustomTag()));
-        if (computationalDAO.addComputational(userInfo.getName(), form.getNotebookName(), project, compResource)) {
-            try {
-                EndpointDTO endpointDTO = endpointService.get(instance.getEndpoint());
-                ComputationalBase<?> dto = requestBuilder.newComputationalCreate(userInfo, projectDTO, instance, form, endpointDTO);
-
-				String uuid =
-						provisioningService.post(endpointDTO.getUrl() + ComputationalAPI.COMPUTATIONAL_CREATE_SPARK,
-								userInfo.getAccessToken(), dto, String.class);
-				requestId.put(userInfo.getName(), uuid);
-				return true;
-			} catch (RuntimeException e) {
-				try {
-					updateComputationalStatus(userInfo.getName(), project, form.getNotebookName(), form.getName(), FAILED);
-				} catch (DlabException d) {
-					log.error(COULD_NOT_UPDATE_THE_STATUS_MSG_FORMAT, form.getName(), userInfo.getName(), d);
-				}
-	            throw e;
-            }
-        } else {
-	        log.debug("Computational with name {} is already existing for user {}", form.getName(),
-			        userInfo.getName());
-	        return false;
-        }
-	}
-
-	@Audit(action = TERMINATE, type = COMPUTE)
-	@Override
-	public void terminateComputational(@User UserInfo userInfo, String resourceCreator, @Project String project, String exploratoryName, @ResourceName String computationalName,
-	                                   @Info String auditInfo) {
-		try {
-			updateComputationalStatus(resourceCreator, project, exploratoryName, computationalName, TERMINATING);
-
-			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(resourceCreator, userInstanceDTO, compResource, endpointDTO);
-
-			final String provisioningUrl = Optional.ofNullable(DATA_ENGINE_TYPE_TERMINATE_URLS.get(dataEngineType))
-					.orElseThrow(UnsupportedOperationException::new);
-			final String uuid = provisioningService.post(endpointDTO.getUrl() + provisioningUrl, userInfo.getAccessToken(), dto, String.class);
-			requestId.put(resourceCreator, uuid);
-		} catch (RuntimeException re) {
-			try {
-				updateComputationalStatus(resourceCreator, project, exploratoryName, computationalName, FAILED);
-			} catch (DlabException e) {
-				log.error(COULD_NOT_UPDATE_THE_STATUS_MSG_FORMAT, computationalName, resourceCreator, e);
-			}
-			throw re;
-		}
-	}
-
-	@BudgetLimited
-	@Audit(action = CREATE, type = COMPUTE)
-	@Override
-	public boolean createDataEngineService(@User UserInfo userInfo, @ResourceName String resourceName, ComputationalCreateFormDTO formDTO,
-										   UserComputationalResource computationalResource, @Project String project, @Info String auditInfo) {
-		final ProjectDTO projectDTO = projectService.get(project);
-		final UserInstanceDTO instance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), project, formDTO
-				.getNotebookName());
-		final Map<String, String> tags = tagService.getResourceTags(userInfo, instance.getEndpoint(), project,
-				formDTO.getCustomTag());
-		computationalResource.setTags(tags);
-		boolean isAdded = computationalDAO.addComputational(userInfo.getName(), formDTO.getNotebookName(), project,
-				computationalResource);
-
-        if (isAdded) {
-			try {
-				EndpointDTO endpointDTO = endpointService.get(instance.getEndpoint());
-				String uuid =
-						provisioningService.post(endpointDTO.getUrl() + COMPUTATIONAL_CREATE_CLOUD_SPECIFIC,
-								userInfo.getAccessToken(),
-								requestBuilder.newComputationalCreate(userInfo, projectDTO, instance, formDTO, endpointDTO),
-								String.class);
-				requestId.put(userInfo.getName(), uuid);
-				return true;
-			} catch (Exception t) {
-				try {
-					updateComputationalStatus(userInfo.getName(), project, formDTO.getNotebookName(),
-							formDTO.getName(), FAILED);
-				} catch (DlabException e) {
-					log.error(COULD_NOT_UPDATE_THE_STATUS_MSG_FORMAT, formDTO.getName(), userInfo.getName(), e);
-				}
-				throw new DlabException("Could not send request for creation the computational resource " + formDTO
-						.getName() + ": " + t.getLocalizedMessage(), t);
-			}
-        } else {
-	        log.debug("Used existing computational resource {} for user {}", formDTO.getName(), userInfo.getName());
-	        return false;
-        }
-	}
-
-	@Audit(action = STOP, type = COMPUTE)
-	@Override
-	public void stopSparkCluster(@User UserInfo userInfo, String resourceCreator, @Project String project, String expName, @ResourceName String compName, @Info String auditInfo) {
-		final UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(resourceCreator, project, expName, true);
-		final UserInstanceStatus requiredStatus = UserInstanceStatus.RUNNING;
-		if (computationalWithStatusResourceExist(compName, userInstance, requiredStatus)) {
-			log.debug("{} spark cluster {} for userInstance {}", STOPPING.toString(), compName, expName);
-			updateComputationalStatus(resourceCreator, project, expName, compName, STOPPING);
-			EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
-			final String uuid = provisioningService.post(endpointDTO.getUrl() + ComputationalAPI.COMPUTATIONAL_STOP_SPARK,
-					userInfo.getAccessToken(),
-					requestBuilder.newComputationalStop(resourceCreator, userInstance, compName, endpointDTO),
-					String.class);
-			requestId.put(resourceCreator, uuid);
-		} else {
-			throw new IllegalStateException(String.format(DATAENGINE_NOT_PRESENT_FORMAT, requiredStatus.toString(), compName, expName));
-		}
-
-	}
-
-	@BudgetLimited
-	@Audit(action = START, type = COMPUTE)
-	@Override
-	public void startSparkCluster(@User UserInfo userInfo, String expName, @ResourceName String compName, @Project String project, @Info String auditInfo) {
-		final UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), project, expName, true);
-		final UserInstanceStatus requiredStatus = UserInstanceStatus.STOPPED;
-		if (computationalWithStatusResourceExist(compName, userInstance, requiredStatus)) {
-			log.debug("{} spark cluster {} for userInstance {}", STARTING.toString(), compName, expName);
-			updateComputationalStatus(userInfo.getName(), project, expName, compName, STARTING);
-			EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
-			final String uuid = provisioningService.post(endpointDTO.getUrl() + ComputationalAPI.COMPUTATIONAL_START_SPARK,
-					userInfo.getAccessToken(),
-					requestBuilder.newComputationalStart(userInfo, userInstance, compName, endpointDTO),
-					String.class);
-			requestId.put(userInfo.getName(), uuid);
-		} else {
-			throw new IllegalStateException(String.format(DATAENGINE_NOT_PRESENT_FORMAT, requiredStatus.toString(), compName, expName));
-		}
-	}
-
-	@Audit(action = RECONFIGURE, type = COMPUTE)
-	@Override
-	public void updateSparkClusterConfig(@User UserInfo userInfo, @Project String project, String exploratoryName, @ResourceName String computationalName, List<ClusterConfig> config, @Info String auditInfo) {
-		final String userName = userInfo.getName();
-		final String token = userInfo.getAccessToken();
-		final UserInstanceDTO userInstanceDTO = exploratoryDAO
-				.fetchExploratoryFields(userName, project, exploratoryName, true);
-		final UserComputationalResource compResource = userInstanceDTO
-				.getResources()
-				.stream()
-				.filter(cr -> cr.getComputationalName().equals(computationalName) && cr.getStatus().equals(UserInstanceStatus.RUNNING.toString()))
-				.findAny()
-				.orElseThrow(() -> new ResourceNotFoundException(String.format(RUNNING_COMP_RES_NOT_FOUND,
-						computationalName, exploratoryName)));
-		EndpointDTO endpointDTO = endpointService.get(userInstanceDTO.getEndpoint());
-		final ComputationalClusterConfigDTO clusterConfigDto = requestBuilder.newClusterConfigUpdate(userInfo,
-				userInstanceDTO, compResource, config, endpointDTO);
-		final String uuid =
-				provisioningService.post(endpointDTO.getUrl() + ComputationalAPI.COMPUTATIONAL_RECONFIGURE_SPARK,
-						token, clusterConfigDto, String.class);
-		computationalDAO.updateComputationalFields(new ComputationalStatusDTO()
-				.withProject(userInstanceDTO.getProject())
-				.withComputationalName(computationalName)
-				.withExploratoryName(exploratoryName)
-				.withConfig(config)
-				.withStatus(RECONFIGURING.toString())
-				.withUser(userName));
-		requestId.put(userName, uuid);
-
-	}
-
-	/**
-	 * Returns computational resource's data by name for user's exploratory.
-	 *
-	 * @param user              user
-	 * @param project           name of project
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @return corresponding computational resource's data or empty data if resource doesn't exist.
-	 */
-	@Override
-	public Optional<UserComputationalResource> getComputationalResource(String user, String project, String exploratoryName, String computationalName) {
-		try {
-			return Optional.of(computationalDAO.fetchComputationalFields(user, project, exploratoryName, computationalName));
-		} catch (DlabException e) {
-			log.warn("Computational resource {} affiliated with exploratory {} for user {} not found.", computationalName, exploratoryName, user, e);
-		}
-		return Optional.empty();
-	}
-
-	@Override
-	public List<ClusterConfig> getClusterConfig(UserInfo userInfo, String project, String exploratoryName, String computationalName) {
-		return computationalDAO.getClusterConfig(userInfo.getName(), project, exploratoryName, computationalName);
-	}
-
-	/**
-	 * Updates the status of computational resource in database.
-	 *
-	 * @param user              user name.
-	 * @param project           project name
-	 * @param exploratoryName   name of exploratory.
-	 * @param computationalName name of computational resource.
-	 * @param status            status
-	 */
-	private void updateComputationalStatus(String user, String project, String exploratoryName, String computationalName, UserInstanceStatus status) {
-		ComputationalStatusDTO computationalStatus = new ComputationalStatusDTO()
-				.withUser(user)
-				.withProject(project)
-				.withExploratoryName(exploratoryName)
-				.withComputationalName(computationalName)
-				.withStatus(status);
-
-		computationalDAO.updateComputationalStatus(computationalStatus);
-	}
-
-	private SparkStandaloneClusterResource createInitialComputationalResource(SparkStandaloneClusterCreateForm form) {
-		return SparkStandaloneClusterResource.builder()
-				.computationalName(form.getName())
-				.imageName(form.getImage())
-				.templateName(form.getTemplateName())
-				.status(CREATING.toString())
-				.dataEngineInstanceCount(form.getDataEngineInstanceCount())
-				.dataEngineInstanceShape(form.getDataEngineInstanceShape())
-				.config(form.getConfig())
-				.build();
-	}
-
-	private boolean computationalWithStatusResourceExist(String compName, UserInstanceDTO ui, UserInstanceStatus status) {
-		return ui.getResources()
-				.stream()
-				.anyMatch(c -> computationalWithNameAndStatus(compName, c, status));
-	}
-
-	private boolean computationalWithNameAndStatus(String computationalName, UserComputationalResource compResource, UserInstanceStatus status) {
-		return compResource.getStatus().equals(status.toString()) &&
-				compResource.getDataEngineType() == SPARK_STANDALONE &&
-				compResource.getComputationalName().equals(computationalName);
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EndpointServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EndpointServiceImpl.java
deleted file mode 100644
index 9c0b35e..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EndpointServiceImpl.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.annotation.Audit;
-import com.epam.dlab.backendapi.annotation.ResourceName;
-import com.epam.dlab.backendapi.annotation.User;
-import com.epam.dlab.backendapi.dao.EndpointDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.UserRoleDAO;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.EndpointResourcesDTO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceConflictException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.ws.rs.core.Response;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.CONNECT;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.DISCONNECT;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.ENDPOINT;
-
-
-@Slf4j
-public class EndpointServiceImpl implements EndpointService {
-	private static final String HEALTH_CHECK = "healthcheck";
-	private final EndpointDAO endpointDAO;
-	private final ProjectService projectService;
-	private final ExploratoryDAO exploratoryDAO;
-	private final RESTService provisioningService;
-	private final UserRoleDAO userRoleDao;
-
-	@Inject
-	public EndpointServiceImpl(EndpointDAO endpointDAO, ProjectService projectService, ExploratoryDAO exploratoryDAO,
-	                           @Named(ServiceConsts.PROVISIONING_SERVICE_NAME) RESTService provisioningService,
-	                           UserRoleDAO userRoleDao) {
-
-		this.endpointDAO = endpointDAO;
-		this.projectService = projectService;
-		this.exploratoryDAO = exploratoryDAO;
-		this.provisioningService = provisioningService;
-		this.userRoleDao = userRoleDao;
-	}
-
-	@Override
-	public List<EndpointDTO> getEndpoints() {
-		return endpointDAO.getEndpoints();
-	}
-
-	@Override
-	public List<EndpointDTO> getEndpointsWithStatus(EndpointDTO.EndpointStatus status) {
-		return endpointDAO.getEndpointsWithStatus(status.name());
-	}
-
-	@Override
-	public EndpointResourcesDTO getEndpointResources(String endpoint) {
-		List<UserInstanceDTO> exploratories = exploratoryDAO.fetchExploratoriesByEndpointWhereStatusNotIn(endpoint,
-				Arrays.asList(UserInstanceStatus.TERMINATED, UserInstanceStatus.FAILED));
-
-		List<ProjectDTO> projects = projectService.getProjectsByEndpoint(endpoint);
-
-		return new EndpointResourcesDTO(exploratories, projects);
-	}
-
-	@Override
-	public EndpointDTO get(String name) {
-		return endpointDAO.get(name)
-				.orElseThrow(() -> new ResourceNotFoundException("Endpoint with name " + name + " not found"));
-	}
-
-	/**
-	 * Create new endpoint object in the System.
-	 * The Endpoint objects should contain Unique values of the 'url' and 'name' fields,
-	 * i.e two objects with same URLs should not be created in the system.
-	 *
-	 * @param userInfo     user properties
-	 * @param resourceName name of the endpoint
-	 * @param endpointDTO  object with endpoint fields
-	 */
-	@Audit(action = CONNECT, type = ENDPOINT)
-	@Override
-	public void create(@User UserInfo userInfo, @ResourceName String resourceName, EndpointDTO endpointDTO) {
-		if (endpointDAO.get(endpointDTO.getName()).isPresent()) {
-			throw new ResourceConflictException("The Endpoint with this name exists in system");
-		}
-		if (endpointDAO.getEndpointWithUrl(endpointDTO.getUrl()).isPresent()) {
-			throw new ResourceConflictException("The Endpoint URL with this address exists in system");
-		}
-		CloudProvider cloudProvider = checkUrl(userInfo, endpointDTO.getUrl());
-		if (Objects.isNull(cloudProvider)) {
-			throw new DlabException("CloudProvider cannot be null");
-		}
-		endpointDAO.create(new EndpointDTO(endpointDTO.getName(), endpointDTO.getUrl(), endpointDTO.getAccount(),
-				endpointDTO.getTag(), EndpointDTO.EndpointStatus.ACTIVE, cloudProvider));
-		userRoleDao.updateMissingRoles(cloudProvider);
-	}
-
-	@Override
-	public void updateEndpointStatus(String name, EndpointDTO.EndpointStatus status) {
-		endpointDAO.updateEndpointStatus(name, status.name());
-	}
-
-	@Override
-	public void remove(UserInfo userInfo, String name) {
-		EndpointDTO endpointDTO = endpointDAO.get(name).orElseThrow(() -> new ResourceNotFoundException(String.format("Endpoint %s does not exist", name)));
-		List<ProjectDTO> projects = projectService.getProjectsByEndpoint(name);
-		checkProjectEndpointResourcesStatuses(projects, name);
-		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
-		removeEndpoint(userInfo, name, cloudProvider, projects);
-	}
-
-	@Audit(action = DISCONNECT, type = ENDPOINT)
-	public void removeEndpoint(@User UserInfo userInfo, @ResourceName String name, CloudProvider cloudProvider, List<ProjectDTO> projects) {
-		removeEndpointInAllProjects(userInfo, name, projects);
-		endpointDAO.remove(name);
-		List<CloudProvider> remainingProviders = endpointDAO.getEndpoints()
-				.stream()
-				.map(EndpointDTO::getCloudProvider)
-				.collect(Collectors.toList());
-		userRoleDao.removeUnnecessaryRoles(cloudProvider, remainingProviders);
-	}
-
-	@Override
-	public void removeEndpointInAllProjects(UserInfo userInfo, String endpointName, List<ProjectDTO> projects) {
-		projects.forEach(project -> projectService.terminateEndpoint(userInfo, endpointName, project.getName()));
-	}
-
-	@Override
-	public CloudProvider checkUrl(UserInfo userInfo, String url) {
-		Response response;
-		CloudProvider cloudProvider;
-		try {
-			response = provisioningService.get(url + HEALTH_CHECK, userInfo.getAccessToken(), Response.class);
-			cloudProvider = response.readEntity(CloudProvider.class);
-		} catch (Exception e) {
-			log.error("Cannot connect to url '{}'. {}", url, e.getMessage(), e);
-			throw new DlabException(String.format("Cannot connect to url '%s'.", url));
-		}
-		if (response.getStatus() != 200) {
-			log.warn("Endpoint url {} is not valid", url);
-			throw new ResourceNotFoundException(String.format("Endpoint url '%s' is not valid", url));
-		}
-		return cloudProvider;
-	}
-
-	private void checkProjectEndpointResourcesStatuses(List<ProjectDTO> projects, String endpoint) {
-		boolean isTerminationEnabled = projects.stream()
-				.anyMatch(p -> !projectService.checkExploratoriesAndComputationalProgress(p.getName(), Collections.singletonList(endpoint)) ||
-						p.getEndpoints().stream()
-								.anyMatch(e -> e.getName().equals(endpoint) &&
-										Arrays.asList(UserInstanceStatus.CREATING, UserInstanceStatus.STARTING, UserInstanceStatus.STOPPING,
-												UserInstanceStatus.TERMINATING).contains(e.getStatus())));
-
-		if (isTerminationEnabled) {
-			throw new ResourceConflictException(("Can not terminate resources of endpoint because one of project " +
-					"resource is in processing stage"));
-		}
-	}
-}
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
deleted file mode 100644
index 95681de..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.annotation.Project;
-import com.epam.dlab.backendapi.annotation.ProjectAdmin;
-import com.epam.dlab.backendapi.annotation.User;
-import com.epam.dlab.backendapi.dao.EnvDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.UserSettingsDAO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.resources.dto.UserDTO;
-import com.epam.dlab.backendapi.resources.dto.UserResourceInfo;
-import com.epam.dlab.backendapi.service.ComputationalService;
-import com.epam.dlab.backendapi.service.EnvironmentService;
-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.dto.UserInstanceDTO;
-import com.epam.dlab.exceptions.ResourceConflictException;
-import com.epam.dlab.model.ResourceEnum;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-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.dto.UserInstanceStatus.CREATING;
-import static com.epam.dlab.dto.UserInstanceStatus.CREATING_IMAGE;
-import static com.epam.dlab.dto.UserInstanceStatus.RUNNING;
-import static com.epam.dlab.dto.UserInstanceStatus.STARTING;
-import static com.epam.dlab.rest.contracts.ComputationalAPI.AUDIT_MESSAGE;
-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 AUDIT_QUOTA_MESSAGE = "Billing quota reached";
-	private static final String DLAB_SYSTEM_USER = "DLab system user";
-
-	private final EnvDAO envDAO;
-	private final UserSettingsDAO settingsDAO;
-	private final ExploratoryDAO exploratoryDAO;
-	private final ExploratoryService exploratoryService;
-	private final ComputationalService computationalService;
-	private final SecurityService securityService;
-	private final ProjectService projectService;
-
-	@Inject
-	public EnvironmentServiceImpl(EnvDAO envDAO, UserSettingsDAO settingsDAO, ExploratoryDAO exploratoryDAO,
-								  ExploratoryService exploratoryService, ComputationalService computationalService,
-								  SecurityService securityService, ProjectService projectService) {
-		this.envDAO = envDAO;
-		this.settingsDAO = settingsDAO;
-		this.exploratoryDAO = exploratoryDAO;
-		this.exploratoryService = exploratoryService;
-		this.computationalService = computationalService;
-		this.securityService = securityService;
-		this.projectService = projectService;
-	}
-
-	@Override
-	public List<UserDTO> getUsers() {
-		final Set<String> activeUsers = envDAO.fetchActiveEnvUsers();
-		log.trace("Active users: {}", activeUsers);
-		final Set<String> notActiveUsers = envDAO.fetchUsersNotIn(activeUsers);
-		log.trace("Not active users: {}", notActiveUsers);
-		final Stream<UserDTO> activeUsersStream = activeUsers
-				.stream()
-				.map(u -> toUserDTO(u, ACTIVE));
-		final Stream<UserDTO> notActiveUsersStream = notActiveUsers
-				.stream()
-				.map(u -> toUserDTO(u, NOT_ACTIVE));
-		return Stream.concat(activeUsersStream, notActiveUsersStream)
-				.collect(toList());
-	}
-
-	@Override
-	public List<UserResourceInfo> getAllEnv(UserInfo user) {
-		log.debug("Getting all user's environment...");
-		List<UserInstanceDTO> expList = exploratoryDAO.getInstances();
-		return projectService.getProjects(user)
-				.stream()
-				.map(projectDTO -> getProjectEnv(projectDTO, expList))
-				.flatMap(Collection::stream)
-				.collect(toList());
-	}
-
-	@Override
-	public void stopAll() {
-		log.debug("Stopping environment for all users...");
-		projectService.getProjects()
-				.stream()
-				.map(ProjectDTO::getName)
-				.forEach(this::stopProjectEnvironment);
-	}
-
-	@Override
-	public void stopEnvironmentWithServiceAccount(String user) {
-		log.debug("Stopping environment for user {} by scheduler", user);
-		checkState(user, "stop");
-		exploratoryDAO.fetchRunningExploratoryFields(user)
-				.forEach(this::stopNotebookWithServiceAccount);
-	}
-
-	@Override
-	public void stopProjectEnvironment(String project) {
-		log.debug("Stopping environment for project {}", project);
-		checkProjectResourceConditions(project, "stop");
-		exploratoryDAO.fetchRunningExploratoryFieldsForProject(project)
-				.forEach(this::stopNotebookWithServiceAccount);
-
-		projectService.get(project).getEndpoints()
-				.stream()
-				.filter(e -> RUNNING == e.getStatus())
-                .forEach(endpoint -> projectService.stop(securityService.getServiceAccountInfo(DLAB_SYSTEM_USER),
-                        endpoint.getName(), project, AUDIT_QUOTA_MESSAGE));
-	}
-
-	@ProjectAdmin
-	@Override
-	public void stopExploratory(@User UserInfo userInfo, String user, @Project String project, String exploratoryName) {
-		exploratoryService.stop(userInfo, user, project, exploratoryName, null);
-	}
-
-	@ProjectAdmin
-    @Override
-    public void stopComputational(@User UserInfo userInfo, String user, @Project String project, String exploratoryName, String computationalName) {
-        computationalService.stopSparkCluster(userInfo, user, project, exploratoryName, computationalName,
-                String.format(AUDIT_MESSAGE, exploratoryName));
-    }
-
-	@ProjectAdmin
-	@Override
-	public void terminateExploratory(@User UserInfo userInfo, String user, @Project String project, String exploratoryName) {
-		exploratoryService.terminate(userInfo, user, project, exploratoryName, null);
-	}
-
-	@ProjectAdmin
-	@Override
-	public void terminateComputational(@User UserInfo userInfo, String user, @Project String project, String exploratoryName, String computationalName) {
-        computationalService.terminateComputational(userInfo, user, project, exploratoryName, computationalName, String.format(AUDIT_MESSAGE, exploratoryName));
-    }
-
-	private UserDTO toUserDTO(String u, UserDTO.Status status) {
-		return new UserDTO(u, settingsDAO.getAllowedBudget(u).orElse(null), status);
-	}
-
-	private void checkState(String user, String action) {
-		final List<UserInstanceDTO> userInstances = exploratoryDAO.fetchUserExploratoriesWhereStatusIn(user, Arrays.asList(CREATING, STARTING, CREATING_IMAGE),
-				CREATING, STARTING, CREATING_IMAGE);
-		if (!userInstances.isEmpty()) {
-			log.error(String.format(ERROR_MSG_FORMAT, action));
-			throw new ResourceConflictException(String.format(ERROR_MSG_FORMAT, action));
-		}
-	}
-
-	private void stopNotebookWithServiceAccount(UserInstanceDTO instance) {
-        final UserInfo userInfo = securityService.getServiceAccountInfo(DLAB_SYSTEM_USER);
-        exploratoryService.stop(userInfo, instance.getUser(), instance.getProject(), instance.getExploratoryName(), AUDIT_QUOTA_MESSAGE);
-    }
-
-	private List<UserResourceInfo> getProjectEnv(ProjectDTO projectDTO, List<UserInstanceDTO> allInstances) {
-		final Stream<UserResourceInfo> userResources = allInstances
-				.stream()
-				.filter(instance -> instance.getProject().equals(projectDTO.getName()))
-				.map(this::toUserResourceInfo);
-		if (projectDTO.getEndpoints() != null) {
-			final Stream<UserResourceInfo> edges = projectDTO.getEndpoints()
-					.stream()
-					.map(e -> UserResourceInfo.builder()
-							.resourceType(ResourceEnum.EDGE_NODE)
-							.resourceStatus(e.getStatus().toString())
-							.project(projectDTO.getName())
-							.endpoint(e.getName())
-							.ip(e.getEdgeInfo() != null ? e.getEdgeInfo().getPublicIp() : null)
-							.build());
-			return Stream.concat(edges, userResources).collect(toList());
-		} else {
-			return userResources.collect(toList());
-		}
-	}
-
-	private UserResourceInfo toUserResourceInfo(UserInstanceDTO userInstance) {
-		return UserResourceInfo.builder()
-				.resourceType(ResourceEnum.NOTEBOOK)
-				.resourceName(userInstance.getExploratoryName())
-				.resourceShape(userInstance.getShape())
-				.resourceStatus(userInstance.getStatus())
-				.computationalResources(userInstance.getResources())
-				.user(userInstance.getUser())
-				.project(userInstance.getProject())
-				.endpoint(userInstance.getEndpoint())
-				.cloudProvider(userInstance.getCloudProvider())
-				.exploratoryUrls(userInstance.getResourceUrl())
-				.build();
-	}
-
-	private void checkProjectResourceConditions(String project, String action) {
-		final List<UserInstanceDTO> userInstances = exploratoryDAO.fetchProjectExploratoriesWhereStatusIn(project,
-				Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE);
-
-		if (!userInstances.isEmpty()) {
-			log.error(String.format(ERROR_MSG_FORMAT, action));
-			throw new ResourceConflictException(String.format(ERROR_MSG_FORMAT, action));
-		}
-	}
-}
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
deleted file mode 100644
index cdafb03..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * 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.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.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.ComputationalDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.GitCredsDAO;
-import com.epam.dlab.backendapi.dao.ImageExploratoryDAO;
-import com.epam.dlab.backendapi.domain.AuditActionEnum;
-import com.epam.dlab.backendapi.domain.AuditDTO;
-import com.epam.dlab.backendapi.domain.AuditResourceTypeEnum;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.resources.dto.ExploratoryCreatePopUp;
-import com.epam.dlab.backendapi.service.AuditService;
-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.TagService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.constants.ServiceConsts;
-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.base.DataEngineType;
-import com.epam.dlab.dto.exploratory.ExploratoryActionDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryStatusDTO;
-import com.epam.dlab.dto.exploratory.LibInstallDTO;
-import com.epam.dlab.dto.exploratory.LibStatus;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.model.exploratory.Exploratory;
-import com.epam.dlab.model.library.Library;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.CREATE;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.RECONFIGURE;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.START;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.STOP;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.TERMINATE;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.NOTEBOOK;
-import static com.epam.dlab.dto.UserInstanceStatus.CREATING;
-import static com.epam.dlab.dto.UserInstanceStatus.FAILED;
-import static com.epam.dlab.dto.UserInstanceStatus.RUNNING;
-import static com.epam.dlab.dto.UserInstanceStatus.STARTING;
-import static com.epam.dlab.dto.UserInstanceStatus.STOPPED;
-import static com.epam.dlab.dto.UserInstanceStatus.STOPPING;
-import static com.epam.dlab.dto.UserInstanceStatus.TERMINATED;
-import static com.epam.dlab.dto.UserInstanceStatus.TERMINATING;
-import static com.epam.dlab.rest.contracts.ExploratoryAPI.EXPLORATORY_CREATE;
-import static com.epam.dlab.rest.contracts.ExploratoryAPI.EXPLORATORY_RECONFIGURE_SPARK;
-import static com.epam.dlab.rest.contracts.ExploratoryAPI.EXPLORATORY_START;
-import static com.epam.dlab.rest.contracts.ExploratoryAPI.EXPLORATORY_STOP;
-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;
-	private final AuditService auditService;
-	private final SelfServiceApplicationConfiguration configuration;
-
-	@Inject
-	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, AuditService auditService,
-	                              SelfServiceApplicationConfiguration configuration) {
-		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;
-		this.auditService = auditService;
-		this.configuration = configuration;
-	}
-
-	@BudgetLimited
-	@Audit(action = START, type = NOTEBOOK)
-	@Override
-	public String start(@User UserInfo userInfo, @ResourceName String exploratoryName, @Project String project, @Info String auditInfo) {
-		return action(userInfo, userInfo.getName(), project, exploratoryName, EXPLORATORY_START, STARTING);
-	}
-
-	@Audit(action = STOP, type = NOTEBOOK)
-	@Override
-	public String stop(@User UserInfo userInfo, String resourceCreator, @Project String project, @ResourceName String exploratoryName, @Info String auditInfo) {
-		return action(userInfo, resourceCreator, project, exploratoryName, EXPLORATORY_STOP, STOPPING);
-	}
-
-	@Audit(action = TERMINATE, type = NOTEBOOK)
-	@Override
-	public String terminate(@User UserInfo userInfo, String resourceCreator, @Project String project, @ResourceName String exploratoryName, @Info String auditInfo) {
-		return action(userInfo, resourceCreator, project, exploratoryName, EXPLORATORY_TERMINATE, TERMINATING);
-	}
-
-	@BudgetLimited
-	@Audit(action = CREATE, type = NOTEBOOK)
-	@Override
-	public String create(@User UserInfo userInfo, Exploratory exploratory, @Project String project, @ResourceName String exploratoryName) {
-		boolean isAdded = false;
-		try {
-			final ProjectDTO projectDTO = projectService.get(project);
-			final EndpointDTO endpointDTO = endpointService.get(exploratory.getEndpoint());
-			final UserInstanceDTO userInstanceDTO = getUserInstanceDTO(userInfo, exploratory, project, endpointDTO.getCloudProvider());
-			exploratoryDAO.insertExploratory(userInstanceDTO);
-			isAdded = true;
-			final ExploratoryGitCredsDTO gitCreds = gitCredsDAO.findGitCreds(userInfo.getName());
-			log.debug("Created exploratory environment {} for user {}", exploratory.getName(), userInfo.getName());
-			final String uuid =
-					provisioningService.post(endpointDTO.getUrl() + EXPLORATORY_CREATE,
-							userInfo.getAccessToken(),
-							requestBuilder.newExploratoryCreate(projectDTO, endpointDTO, exploratory, userInfo,
-									gitCreds, userInstanceDTO.getTags()),
-							String.class);
-			requestId.put(userInfo.getName(), uuid);
-			return uuid;
-		} catch (Exception t) {
-			log.error("Could not update the status of exploratory environment {} with name {} for user {}",
-					exploratory.getDockerImage(), exploratory.getName(), userInfo.getName(), t);
-			if (isAdded) {
-				updateExploratoryStatusSilent(userInfo.getName(), project, exploratory.getName(), FAILED);
-			}
-			throw new DlabException("Could not create exploratory environment " + exploratory.getName() + " for user "
-					+ userInfo.getName() + ": " + Optional.ofNullable(t.getCause()).map(Throwable::getMessage).orElse(t.getMessage()), t);
-		}
-	}
-
-	@Override
-	public void updateProjectExploratoryStatuses(UserInfo userInfo, String project, String endpoint, UserInstanceStatus status) {
-		exploratoryDAO.fetchProjectExploratoriesWhereStatusNotIn(project, endpoint, TERMINATED, FAILED)
-				.forEach(ui -> updateExploratoryComputeStatuses(userInfo, project, ui.getExploratoryName(), status, ui.getUser()));
-	}
-
-	@Override
-	public void updateProjectExploratoryStatuses(String project, String endpoint, UserInstanceStatus status) {
-		exploratoryDAO.fetchProjectExploratoriesWhereStatusNotIn(project, endpoint, TERMINATED, FAILED)
-				.forEach(ui -> {
-					updateExploratoryStatus(ui.getUser(), project, ui.getExploratoryName(), status);
-					updateComputationalStatuses(ui.getUser(), project, ui.getExploratoryName(), TERMINATED, TERMINATED, TERMINATED, FAILED);
-				});
-	}
-
-	@Audit(action = RECONFIGURE, type = NOTEBOOK)
-	@Override
-	public void updateClusterConfig(@User UserInfo userInfo, @Project 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);
-		EndpointDTO endpointDTO = endpointService.get(userInstanceDTO.getEndpoint());
-		final ExploratoryReconfigureSparkClusterActionDTO updateClusterConfigDTO =
-				requestBuilder.newClusterConfigUpdate(userInfo, userInstanceDTO, config, endpointDTO);
-		final String uuid = provisioningService.post(endpointDTO.getUrl() + EXPLORATORY_RECONFIGURE_SPARK,
-				token, updateClusterConfigDTO,
-				String.class);
-		requestId.put(userName, uuid);
-		exploratoryDAO.updateExploratoryFields(new ExploratoryStatusDTO()
-				.withUser(userName)
-				.withProject(project)
-				.withExploratoryName(exploratoryName)
-				.withConfig(config)
-				.withStatus(UserInstanceStatus.RECONFIGURING.toString()));
-	}
-
-	/**
-	 * Returns user instance's data by it's name.
-	 *
-	 * @param user            user.
-	 * @param project
-	 * @param exploratoryName name of exploratory.
-	 * @return corresponding user instance's data or empty data if resource doesn't exist.
-	 */
-	@Override
-	public Optional<UserInstanceDTO> getUserInstance(String user, String project, String exploratoryName) {
-		try {
-			return Optional.of(exploratoryDAO.fetchExploratoryFields(user, project, exploratoryName));
-		} catch (DlabException e) {
-			log.warn("User instance with exploratory {}, project {} for user {} not found.", exploratoryName, project, user, e);
-		}
-		return Optional.empty();
-	}
-
-	@Override
-	public Optional<UserInstanceDTO> getUserInstance(String user, String project, String exploratoryName, boolean includeCompResources) {
-		try {
-			return Optional.of(exploratoryDAO.fetchExploratoryFields(user, project, exploratoryName, includeCompResources));
-		} catch (DlabException e) {
-			log.warn("User instance with exploratory {}, project {} for user {} not found.", exploratoryName, project, user, e);
-		}
-		return Optional.empty();
-	}
-
-	@Override
-	public List<UserInstanceDTO> findAll() {
-		return exploratoryDAO.getInstances();
-	}
-
-	@Override
-	public List<UserInstanceDTO> findAll(Set<ProjectDTO> projects) {
-		List<String> projectNames = projects
-				.stream()
-				.map(ProjectDTO::getName)
-				.collect(Collectors.toList());
-		return exploratoryDAO.fetchExploratoryFieldsForProjectWithComp(projectNames);
-	}
-
-	@Override
-	public List<ClusterConfig> getClusterConfig(UserInfo user, String project, String exploratoryName) {
-		return exploratoryDAO.getClusterConfig(user.getName(), project, exploratoryName);
-	}
-
-	@Override
-	public ExploratoryCreatePopUp getUserInstances(UserInfo user) {
-		List<ProjectDTO> userProjects = projectService.getUserProjects(user, false);
-		Map<String, List<String>> collect = userProjects.stream()
-				.collect(Collectors.toMap(ProjectDTO::getName, this::getProjectExploratoryNames));
-		return new ExploratoryCreatePopUp(userProjects, collect);
-	}
-
-	private List<String> getProjectExploratoryNames(ProjectDTO project) {
-		return exploratoryDAO.fetchExploratoryFieldsForProject(project.getName()).stream()
-				.map(UserInstanceDTO::getExploratoryName)
-				.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 resourceCreator, String project, String exploratoryName, String action, UserInstanceStatus status) {
-		try {
-			updateExploratoryComputeStatuses(userInfo.getName(), project, exploratoryName, status, resourceCreator);
-
-			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, 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, 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()));
-			throw new DlabException(errorMsg, t);
-		}
-	}
-
-	@Audit(action = TERMINATE, type = NOTEBOOK)
-	public void updateExploratoryComputeStatuses(@User UserInfo userInfo, @Project String project, @ResourceName String exploratoryName, UserInstanceStatus status, String resourceCreator) {
-		updateExploratoryStatus(resourceCreator, project, exploratoryName, status);
-		updateComputationalStatuses(userInfo.getName(), resourceCreator, project, exploratoryName, status);
-	}
-
-	private void updateExploratoryComputeStatuses(String user, String project, String exploratoryName, UserInstanceStatus status, String resourceCreator) {
-		updateExploratoryStatus(resourceCreator, project, exploratoryName, status);
-		updateComputationalStatuses(user, resourceCreator, project, exploratoryName, status);
-	}
-
-	private void updateComputationalStatuses(String user, String resourceCreator, String project, String exploratoryName, UserInstanceStatus status) {
-		if (status == STOPPING) {
-			if (configuration.isAuditEnabled()) {
-				saveAudit(user, resourceCreator, project, exploratoryName, STOP, RUNNING);
-			}
-			updateComputationalStatuses(resourceCreator, project, exploratoryName, STOPPING, TERMINATING, FAILED, TERMINATED, STOPPED);
-		} else if (status == TERMINATING) {
-			if (configuration.isAuditEnabled()) {
-				saveAudit(user, resourceCreator, project, exploratoryName, TERMINATE, RUNNING, STOPPED);
-			}
-			updateComputationalStatuses(resourceCreator, project, exploratoryName, TERMINATING, TERMINATING, TERMINATED, FAILED);
-		}
-	}
-
-	private void saveAudit(String user, String resourceCreator, String project, String exploratoryName, AuditActionEnum action, UserInstanceStatus... sparkStatuses) {
-		saveAuditForComputational(user, resourceCreator, project, exploratoryName, action, DataEngineType.SPARK_STANDALONE, sparkStatuses);
-		saveAuditForComputational(user, resourceCreator, project, exploratoryName, TERMINATE, DataEngineType.CLOUD_SERVICE, RUNNING, STOPPED);
-	}
-
-	private void saveAuditForComputational(String user, String resourceCreator, String project, String exploratoryName, AuditActionEnum action, DataEngineType cloudService,
-	                                       UserInstanceStatus... computationalStatuses) {
-		computationalDAO.getComputationalResourcesWhereStatusIn(resourceCreator, project, Collections.singletonList(cloudService),
-				exploratoryName, computationalStatuses)
-				.forEach(comp -> auditService.save(
-						AuditDTO.builder()
-								.user(user)
-								.resourceName(comp)
-								.project(project)
-								.action(action)
-								.type(AuditResourceTypeEnum.COMPUTE)
-								.build())
-				);
-	}
-
-	private ExploratoryActionDTO<?> getExploratoryActionDto(UserInfo userInfo, String resourceCreator, UserInstanceStatus status, UserInstanceDTO userInstance,
-															EndpointDTO endpointDTO) {
-		ExploratoryActionDTO<?> dto;
-		if (status != UserInstanceStatus.STARTING) {
-			dto = requestBuilder.newExploratoryStop(resourceCreator, userInstance, endpointDTO);
-		} else {
-			dto = requestBuilder.newExploratoryStart(userInfo, userInstance, endpointDTO, gitCredsDAO.findGitCreds(userInfo.getName()));
-		}
-		return dto;
-	}
-
-
-	/**
-	 * Updates the status of exploratory environment.
-	 *
-	 * @param user            user name
-	 * @param project         project name
-	 * @param exploratoryName name of exploratory environment.
-	 * @param status          status for exploratory environment.
-	 */
-	private void updateExploratoryStatus(String user, String project, String exploratoryName, UserInstanceStatus status) {
-		StatusEnvBaseDTO<?> exploratoryStatus = createStatusDTO(user, project, exploratoryName, status);
-		exploratoryDAO.updateExploratoryStatus(exploratoryStatus);
-	}
-
-	/**
-	 * Updates the status of exploratory environment without exceptions. If exception occurred then logging it.
-	 *
-	 * @param user            user name
-	 * @param project         project name
-	 * @param exploratoryName name of exploratory environment.
-	 * @param status          status for exploratory environment.
-	 */
-	private void updateExploratoryStatusSilent(String user, String project, String exploratoryName, UserInstanceStatus status) {
-		try {
-			updateExploratoryStatus(user, project, exploratoryName, status);
-		} catch (DlabException e) {
-			log.error("Could not update the status of exploratory environment {} for user {} to {}",
-					exploratoryName, user, status, e);
-		}
-	}
-
-	private void updateComputationalStatuses(String user, String project, String exploratoryName, UserInstanceStatus
-			dataEngineStatus, UserInstanceStatus dataEngineServiceStatus, UserInstanceStatus... excludedStatuses) {
-		log.debug("updating status for all computational resources of {} for user {}: DataEngine {}, " +
-				"dataengine-service {}", exploratoryName, user, dataEngineStatus, dataEngineServiceStatus);
-		computationalDAO.updateComputationalStatusesForExploratory(user, project, exploratoryName,
-				dataEngineStatus, dataEngineServiceStatus, excludedStatuses);
-	}
-
-	/**
-	 * Instantiates and returns the descriptor of exploratory environment status.
-	 *
-	 * @param user            user name
-	 * @param project         project
-	 * @param exploratoryName name of exploratory environment.
-	 * @param status          status for exploratory environment.
-	 */
-	private StatusEnvBaseDTO<?> createStatusDTO(String user, String project, String exploratoryName, UserInstanceStatus status) {
-		return new ExploratoryStatusDTO()
-				.withUser(user)
-				.withProject(project)
-				.withExploratoryName(exploratoryName)
-				.withStatus(status);
-	}
-
-	private UserInstanceDTO getUserInstanceDTO(UserInfo userInfo, Exploratory exploratory, String project, CloudProvider cloudProvider) {
-		final UserInstanceDTO userInstance = new UserInstanceDTO()
-				.withUser(userInfo.getName())
-				.withExploratoryName(exploratory.getName())
-				.withStatus(CREATING.toString())
-				.withImageName(exploratory.getDockerImage())
-				.withImageVersion(exploratory.getVersion())
-				.withTemplateName(exploratory.getTemplateName())
-				.withClusterConfig(exploratory.getClusterConfig())
-				.withShape(exploratory.getShape())
-				.withProject(project)
-				.withEndpoint(exploratory.getEndpoint())
-				.withCloudProvider(cloudProvider.toString())
-				.withTags(tagService.getResourceTags(userInfo, exploratory.getEndpoint(), project,
-						exploratory.getExploratoryTag()));
-		if (StringUtils.isNotBlank(exploratory.getImageName())) {
-			final List<LibInstallDTO> libInstallDtoList = getImageRelatedLibraries(userInfo, exploratory.getImageName(),
-					project, exploratory.getEndpoint());
-			userInstance.withLibs(libInstallDtoList);
-		}
-		return userInstance;
-	}
-
-	private List<LibInstallDTO> getImageRelatedLibraries(UserInfo userInfo, String imageFullName, String project,
-														 String endpoint) {
-		final List<Library> libraries = imageExploratoryDao.getLibraries(userInfo.getName(), imageFullName, project,
-				endpoint, LibStatus.INSTALLED);
-		return toLibInstallDtoList(libraries);
-	}
-
-	private List<LibInstallDTO> toLibInstallDtoList(List<Library> libraries) {
-		return libraries
-				.stream()
-				.map(this::toLibInstallDto)
-				.collect(Collectors.toList());
-	}
-
-	private LibInstallDTO toLibInstallDto(Library l) {
-		return new LibInstallDTO(l.getGroup(), l.getName(), l.getVersion())
-				.withStatus(String.valueOf(l.getStatus()))
-				.withAddedPackages(l.getAddedPackages())
-				.withErrorMessage(l.getErrorMessage());
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/GitCredentialServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/GitCredentialServiceImpl.java
deleted file mode 100644
index 4b8b604..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/GitCredentialServiceImpl.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.annotation.Audit;
-import com.epam.dlab.backendapi.annotation.User;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.GitCredsDAO;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.GitCredentialService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.UPDATE;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.GIT_ACCOUNT;
-import static com.epam.dlab.rest.contracts.ExploratoryAPI.EXPLORATORY_GIT_CREDS;
-
-@Slf4j
-@Singleton
-public class GitCredentialServiceImpl implements GitCredentialService {
-
-    private static final boolean CLEAR_USER_PASSWORD = true;
-    @Inject
-    private GitCredsDAO gitCredsDAO;
-    @Inject
-    private ExploratoryDAO exploratoryDAO;
-    @Inject
-    @Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
-    private RESTService provisioningService;
-    @Inject
-    private RequestBuilder requestBuilder;
-    @Inject
-    private RequestId requestId;
-    @Inject
-    private EndpointService endpointService;
-
-    @Audit(action = UPDATE, type = GIT_ACCOUNT)
-    @Override
-    public void updateGitCredentials(@User UserInfo userInfo, ExploratoryGitCredsDTO formDTO) {
-        log.debug("Updating GIT creds for user {} to {}", userInfo.getName(), formDTO);
-        try {
-            gitCredsDAO.updateGitCreds(userInfo.getName(), formDTO);
-            final String failedNotebooks = exploratoryDAO.fetchRunningExploratoryFields(userInfo.getName())
-                    .stream()
-                    .filter(ui -> !updateNotebookGitCredentials(userInfo, formDTO, ui))
-                    .map(UserInstanceDTO::getExploratoryName)
-                    .collect(Collectors.joining(","));
-            if (StringUtils.isNotEmpty(failedNotebooks)) {
-                throw new DlabException("Requests for notebooks failed: " + failedNotebooks);
-            }
-        } catch (Exception t) {
-            log.error("Cannot update the GIT creds for user {}", userInfo.getName(), t);
-            throw new DlabException("Cannot update the GIT credentials: " + t.getLocalizedMessage(), t);
-        }
-    }
-
-    @Override
-	public ExploratoryGitCredsDTO getGitCredentials(String user) {
-		log.debug("Loading GIT creds for user {}", user);
-		try {
-			return gitCredsDAO.findGitCreds(user, CLEAR_USER_PASSWORD);
-		} catch (Exception t) {
-			log.error("Cannot load list of GIT creds for user: {}", user, t);
-			throw new DlabException(String.format("Cannot load GIT credentials for user %s: %s",
-					user, t.getLocalizedMessage()), t);
-		}
-	}
-
-	private boolean updateNotebookGitCredentials(UserInfo userInfo, ExploratoryGitCredsDTO formDTO,
-												 UserInstanceDTO instance) {
-		boolean gitCredentialsUpdated = true;
-		try {
-			log.debug("Updating GIT creds for user {} on exploratory {}",
-					userInfo.getName(), instance.getExploratoryName());
-			EndpointDTO endpointDTO = endpointService.get(instance.getEndpoint());
-			ExploratoryGitCredsUpdateDTO dto = requestBuilder.newGitCredentialsUpdate(userInfo, instance, endpointDTO, formDTO);
-			final String uuid = provisioningService.post(endpointDTO.getUrl() + EXPLORATORY_GIT_CREDS,
-							userInfo.getAccessToken(), dto, String.class);
-			requestId.put(userInfo.getName(), uuid);
-		} catch (Exception t) {
-			log.error("Cannot update the GIT creds for user {} on exploratory {}", userInfo.getName(),
-					instance.getExploratoryName(), t);
-			gitCredentialsUpdated = false;
-		}
-		return gitCredentialsUpdated;
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/GuacamoleServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/GuacamoleServiceImpl.java
deleted file mode 100644
index e94bf91..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/GuacamoleServiceImpl.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.GuacamoleService;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.KeyAPI;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.guacamole.net.GuacamoleTunnel;
-import org.apache.guacamole.net.InetGuacamoleSocket;
-import org.apache.guacamole.net.SimpleGuacamoleTunnel;
-import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket;
-import org.apache.guacamole.protocol.GuacamoleConfiguration;
-
-import javax.inject.Named;
-import java.net.URI;
-import java.util.Map;
-
-@Slf4j
-@Singleton
-public class GuacamoleServiceImpl implements GuacamoleService {
-
-	private static final String PRIVATE_KEY_PARAM_NAME = "private-key";
-	private static final String HOSTNAME_PARAM = "hostname";
-	private static final String CONNECTION_PROTOCOL_PARAM = "connectionProtocol";
-	private static final String SERVER_HOST_PARAM = "serverHost";
-	private final SelfServiceApplicationConfiguration conf;
-	private final RESTService provisioningService;
-	private final EndpointService endpointService;
-
-	@Inject
-	public GuacamoleServiceImpl(SelfServiceApplicationConfiguration conf,
-	                            @Named(ServiceConsts.PROVISIONING_SERVICE_NAME) RESTService provisioningService,
-	                            EndpointService endpointService) {
-		this.conf = conf;
-		this.provisioningService = provisioningService;
-		this.endpointService = endpointService;
-	}
-
-	@Override
-	public GuacamoleTunnel getTunnel(UserInfo userInfo, String host, String endpoint) {
-		try {
-			final String url = endpointService.get(endpoint).getUrl();
-			String key = provisioningService.get(url + KeyAPI.GET_ADMIN_KEY,
-					userInfo.getAccessToken(), String.class);
-			final String guacamoleServerHost = new URI(url).getHost();
-			InetGuacamoleSocket socket = new InetGuacamoleSocket(guacamoleServerHost, conf.getGuacamolePort());
-			final Map<String, String> guacamoleConf = conf.getGuacamole();
-			guacamoleConf.put(SERVER_HOST_PARAM, guacamoleServerHost);
-			GuacamoleConfiguration guacamoleConfig = getGuacamoleConfig(key, guacamoleConf, host);
-			return new SimpleGuacamoleTunnel(new ConfiguredGuacamoleSocket(socket, guacamoleConfig));
-		} catch (Exception e) {
-			log.error("Can not create guacamole tunnel due to: " + e.getMessage());
-			throw new DlabException("Can not create guacamole tunnel due to: " + e.getMessage(), e);
-		}
-	}
-
-	private GuacamoleConfiguration getGuacamoleConfig(String privateKeyContent, Map<String, String> guacamoleParams,
-	                                                  String host) {
-		GuacamoleConfiguration guacamoleConfiguration = new GuacamoleConfiguration();
-		guacamoleConfiguration.setProtocol(guacamoleParams.get(CONNECTION_PROTOCOL_PARAM));
-		guacamoleConfiguration.setParameters(guacamoleParams);
-		guacamoleConfiguration.setParameter(HOSTNAME_PARAM, host);
-		guacamoleConfiguration.setParameter(PRIVATE_KEY_PARAM_NAME, privateKeyContent);
-		return guacamoleConfiguration;
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ImageExploratoryServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ImageExploratoryServiceImpl.java
deleted file mode 100644
index 4aae5b1..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ImageExploratoryServiceImpl.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.annotation.Audit;
-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.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryLibDAO;
-import com.epam.dlab.backendapi.dao.ImageExploratoryDAO;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.resources.dto.ImageInfoRecord;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.ImageExploratoryService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.exploratory.ExploratoryStatusDTO;
-import com.epam.dlab.dto.exploratory.ImageStatus;
-import com.epam.dlab.exceptions.ResourceAlreadyExistException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.model.ResourceType;
-import com.epam.dlab.model.exploratory.Image;
-import com.epam.dlab.model.library.Library;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.ExploratoryAPI;
-import com.google.common.collect.Lists;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.List;
-import java.util.Map;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.CREATE;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.IMAGE;
-
-@Singleton
-@Slf4j
-public class ImageExploratoryServiceImpl implements ImageExploratoryService {
-	private static final String IMAGE_EXISTS_MSG = "Image with name %s is already exist in project %s";
-	private static final String IMAGE_NOT_FOUND_MSG = "Image with name %s was not found for user %s";
-
-	@Inject
-	private ExploratoryDAO exploratoryDAO;
-	@Inject
-	private ImageExploratoryDAO imageExploratoryDao;
-	@Inject
-	private ExploratoryLibDAO libDAO;
-	@Inject
-	@Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
-	private RESTService provisioningService;
-	@Inject
-	private RequestBuilder requestBuilder;
-	@Inject
-	private EndpointService endpointService;
-	@Inject
-	private ProjectService projectService;
-
-    @Audit(action = CREATE, type = IMAGE)
-    @Override
-    public String createImage(@User UserInfo user, @Project String project, @ResourceName String exploratoryName, String imageName, String imageDescription, @Info String info) {
-        ProjectDTO projectDTO = projectService.get(project);
-        UserInstanceDTO userInstance = exploratoryDAO.fetchRunningExploratoryFields(user.getName(), project, exploratoryName);
-
-        if (imageExploratoryDao.exist(imageName, userInstance.getProject())) {
-            log.error(String.format(IMAGE_EXISTS_MSG, imageName, userInstance.getProject()));
-            throw new ResourceAlreadyExistException(String.format(IMAGE_EXISTS_MSG, imageName, userInstance.getProject()));
-        }
-        final List<Library> libraries = libDAO.getLibraries(user.getName(), project, exploratoryName);
-
-        imageExploratoryDao.save(Image.builder()
-                .name(imageName)
-                .description(imageDescription)
-                .status(ImageStatus.CREATING)
-                .user(user.getName())
-                .libraries(fetchExploratoryLibs(libraries))
-                .computationalLibraries(fetchComputationalLibs(libraries))
-                .dockerImage(userInstance.getImageName())
-                .exploratoryId(userInstance.getId())
-				.project(userInstance.getProject())
-				.endpoint(userInstance.getEndpoint())
-				.build());
-
-		exploratoryDAO.updateExploratoryStatus(new ExploratoryStatusDTO()
-				.withUser(user.getName())
-				.withProject(project)
-				.withExploratoryName(exploratoryName)
-				.withStatus(UserInstanceStatus.CREATING_IMAGE));
-
-		EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
-		return provisioningService.post(endpointDTO.getUrl() + ExploratoryAPI.EXPLORATORY_IMAGE,
-				user.getAccessToken(),
-				requestBuilder.newExploratoryImageCreate(user, userInstance, imageName, endpointDTO, projectDTO), String.class);
-	}
-
-	@Override
-	public void finishImageCreate(Image image, String exploratoryName, String newNotebookIp) {
-		log.debug("Returning exploratory status with name {} to RUNNING for user {}",
-				exploratoryName, image.getUser());
-		exploratoryDAO.updateExploratoryStatus(new ExploratoryStatusDTO()
-				.withUser(image.getUser())
-				.withProject(image.getProject())
-				.withExploratoryName(exploratoryName)
-				.withStatus(UserInstanceStatus.RUNNING));
-		imageExploratoryDao.updateImageFields(image);
-		if (newNotebookIp != null) {
-			log.debug("Changing exploratory ip with name {} for user {} to {}", exploratoryName, image.getUser(),
-					newNotebookIp);
-			exploratoryDAO.updateExploratoryIp(image.getUser(), image.getProject(), newNotebookIp, exploratoryName);
-		}
-
-	}
-
-	@Override
-	public List<ImageInfoRecord> getNotFailedImages(String user, String dockerImage, String project, String endpoint) {
-		return imageExploratoryDao.getImages(user, dockerImage, project, endpoint, ImageStatus.CREATED, ImageStatus.CREATING);
-	}
-
-	@Override
-	public ImageInfoRecord getImage(String user, String name, String project, String endpoint) {
-		return imageExploratoryDao.getImage(user, name, project, endpoint).orElseThrow(() ->
-				new ResourceNotFoundException(String.format(IMAGE_NOT_FOUND_MSG, name, user)));
-	}
-
-	@Override
-	public List<ImageInfoRecord> getImagesForProject(String project) {
-		return imageExploratoryDao.getImagesForProject(project);
-	}
-
-	private Map<String, List<Library>> fetchComputationalLibs(List<Library> libraries) {
-		return libraries.stream()
-				.filter(resourceTypePredicate(ResourceType.COMPUTATIONAL))
-				.collect(Collectors.toMap(Library::getResourceName, Lists::newArrayList, this::merge));
-	}
-
-	private List<Library> merge(List<Library> oldValue, List<Library> newValue) {
-		oldValue.addAll(newValue);
-		return oldValue;
-	}
-
-	private List<Library> fetchExploratoryLibs(List<Library> libraries) {
-		return libraries.stream()
-				.filter(resourceTypePredicate(ResourceType.EXPLORATORY))
-				.collect(Collectors.toList());
-	}
-
-	private Predicate<Library> resourceTypePredicate(ResourceType resourceType) {
-		return l -> resourceType == l.getType();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InactivityServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InactivityServiceImpl.java
deleted file mode 100644
index dd370dd..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InactivityServiceImpl.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.ComputationalDAO;
-import com.epam.dlab.backendapi.dao.EnvDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.InactivityService;
-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.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.computational.ComputationalCheckInactivityDTO;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.dto.exploratory.ExploratoryCheckInactivityAction;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.InfrasctructureAPI;
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-
-import java.time.LocalDateTime;
-
-@Slf4j
-public class InactivityServiceImpl implements InactivityService {
-	@Inject
-	private ExploratoryDAO exploratoryDAO;
-	@Inject
-	private ComputationalDAO computationalDAO;
-	@Inject
-	private EnvDAO envDAO;
-	@Inject
-	private RequestBuilder requestBuilder;
-	@Inject
-	@Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
-	private RESTService provisioningService;
-	@Inject
-	private RequestId requestId;
-	@Inject
-	private SecurityService securityService;
-	@Inject
-	private EndpointService endpointService;
-
-	@Override
-	public void updateRunningResourcesLastActivity() {
-		envDAO.findRunningResourcesForCheckInactivity()
-				.forEach(this::updateLastActivity);
-	}
-
-	@Override
-	public void updateLastActivityForExploratory(UserInfo userInfo, String exploratoryName,
-												 LocalDateTime lastActivity) {
-		exploratoryDAO.updateLastActivity(userInfo.getName(), exploratoryName, lastActivity);
-	}
-
-	@Override
-	public void updateLastActivityForComputational(UserInfo userInfo, String project, String exploratoryName,
-												   String computationalName, LocalDateTime lastActivity) {
-		computationalDAO.updateLastActivity(userInfo.getName(), project, exploratoryName, computationalName, lastActivity);
-	}
-
-	private void updateLastActivity(UserInstanceDTO ui) {
-		if (UserInstanceStatus.RUNNING.toString().equals(ui.getStatus())) {
-			updateExploratoryLastActivity(securityService.getUserInfoOffline(ui.getUser()), ui);
-		}
-		ui.getResources()
-				.stream()
-				.filter(comp -> UserInstanceStatus.RUNNING.toString().equals(comp.getStatus()))
-				.forEach(cr -> updateComputationalLastActivity(securityService.getUserInfoOffline(ui.getUser()), ui, cr));
-	}
-
-	private void updateComputationalLastActivity(UserInfo userInfo, UserInstanceDTO ui, UserComputationalResource cr) {
-		EndpointDTO endpointDTO = endpointService.get(ui.getEndpoint());
-		final ComputationalCheckInactivityDTO dto = requestBuilder.newComputationalCheckInactivity(userInfo, ui, cr, endpointDTO);
-		final String uuid =
-				provisioningService.post(endpointDTO.getUrl() + InfrasctructureAPI.COMPUTATIONAL_CHECK_INACTIVITY,
-						userInfo.getAccessToken(), dto, String.class);
-		requestId.put(userInfo.getName(), uuid);
-	}
-
-	private void updateExploratoryLastActivity(UserInfo userInfo, UserInstanceDTO ui) {
-		EndpointDTO endpointDTO = endpointService.get(ui.getEndpoint());
-		final ExploratoryCheckInactivityAction dto =
-				requestBuilder.newExploratoryCheckInactivityAction(userInfo, ui, endpointDTO);
-		final String uuid =
-				provisioningService.post(endpointDTO.getUrl() + InfrasctructureAPI.EXPLORATORY_CHECK_INACTIVITY,
-						userInfo.getAccessToken(), dto, String.class);
-		requestId.put(userInfo.getName(), uuid);
-	}
-}
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
deleted file mode 100644
index a368b18..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceImpl.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.domain.BillingReport;
-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.resources.dto.HealthStatusEnum;
-import com.epam.dlab.backendapi.resources.dto.HealthStatusPageDTO;
-import com.epam.dlab.backendapi.resources.dto.ProjectInfrastructureInfo;
-import com.epam.dlab.backendapi.roles.RoleType;
-import com.epam.dlab.backendapi.roles.UserRoles;
-import com.epam.dlab.backendapi.service.BillingService;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.InfrastructureInfoService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.dto.InfrastructureMetaInfoDTO;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.aws.edge.EdgeInfoAws;
-import com.epam.dlab.dto.azure.edge.EdgeInfoAzure;
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.dto.gcp.edge.EdgeInfoGcp;
-import com.google.inject.Inject;
-import com.jcabi.manifests.Manifests;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-@Slf4j
-public class InfrastructureInfoServiceImpl implements InfrastructureInfoService {
-	private static final String RELEASE_NOTES_FORMAT = "https://github.com/apache/incubator-dlab/blob/%s/RELEASE_NOTES.md";
-	private static final String PERMISSION_VIEW = "/api/bucket/view";
-	private static final String PERMISSION_UPLOAD = "/api/bucket/upload";
-	private static final String PERMISSION_DOWNLOAD = "/api/bucket/download";
-	private static final String PERMISSION_DELETE = "/api/bucket/delete";
-
-	private final ExploratoryDAO expDAO;
-	private final SelfServiceApplicationConfiguration configuration;
-	private final ProjectService projectService;
-	private final EndpointService endpointService;
-	private final BillingService billingService;
-
-	@Inject
-	public InfrastructureInfoServiceImpl(ExploratoryDAO expDAO, SelfServiceApplicationConfiguration configuration, ProjectService projectService,
-	                                     EndpointService endpointService, BillingService billingService) {
-		this.expDAO = expDAO;
-		this.configuration = configuration;
-		this.projectService = projectService;
-		this.endpointService = endpointService;
-		this.billingService = billingService;
-	}
-
-	@Override
-	public List<ProjectInfrastructureInfo> getUserResources(UserInfo user) {
-		log.debug("Loading list of provisioned resources for user {}", user);
-		List<EndpointDTO> allEndpoints = endpointService.getEndpoints();
-		return projectService.getUserProjects(user, Boolean.FALSE)
-				.stream()
-				.map(p -> {
-					List<UserInstanceDTO> exploratories = expDAO.findExploratories(user.getName(), p.getName());
-					return ProjectInfrastructureInfo.builder()
-							.project(p.getName())
-							.billingQuoteUsed(billingService.getBillingProjectQuoteUsed(p.getName()))
-							.shared(getSharedInfo(p.getName()))
-							.exploratory(exploratories)
-							.exploratoryBilling(getExploratoryBillingData(exploratories))
-							.endpoints(getEndpoints(allEndpoints, p))
-							.build();
-				})
-				.collect(Collectors.toList());
-	}
-
-	@Override
-	public HealthStatusPageDTO getHeathStatus(UserInfo userInfo) {
-		log.debug("Request the status of resources for user {}", userInfo.getName());
-		return HealthStatusPageDTO.builder()
-				.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))
-				.bucketBrowser(HealthStatusPageDTO.BucketBrowser.builder()
-						.view(checkAccess(userInfo, PERMISSION_VIEW))
-						.upload(checkAccess(userInfo, PERMISSION_UPLOAD))
-						.download(checkAccess(userInfo, PERMISSION_DOWNLOAD))
-						.delete(checkAccess(userInfo, PERMISSION_DELETE))
-						.build())
-				.build();
-	}
-
-	@Override
-	public InfrastructureMetaInfoDTO getInfrastructureMetaInfo() {
-		final String branch = Manifests.read("GIT-Branch");
-		return InfrastructureMetaInfoDTO.builder()
-				.branch(branch)
-				.commit(Manifests.read("GIT-Commit"))
-				.version(Manifests.read("DLab-Version"))
-				.releaseNotes(String.format(RELEASE_NOTES_FORMAT, branch))
-				.build();
-	}
-
-	private List<BillingReport> getExploratoryBillingData(List<UserInstanceDTO> exploratories) {
-		return exploratories
-				.stream()
-				.map(exp -> billingService.getExploratoryBillingData(exp.getProject(), exp.getEndpoint(),
-						exp.getExploratoryName(), exp.getResources()
-								.stream()
-								.map(UserComputationalResource::getComputationalName)
-								.collect(Collectors.toList())
-				))
-				.collect(Collectors.toList());
-	}
-
-	private List<EndpointDTO> getEndpoints(List<EndpointDTO> allEndpoints, ProjectDTO projectDTO) {
-		return allEndpoints
-				.stream()
-				.filter(endpoint -> projectDTO.getEndpoints()
-						.stream()
-						.anyMatch(endpoint1 -> endpoint1.getName().equals(endpoint.getName())))
-				.collect(Collectors.toList());
-	}
-
-	private Map<String, Map<String, String>> getSharedInfo(String name) {
-		return projectService.get(name).getEndpoints()
-				.stream()
-				.collect(Collectors.toMap(ProjectEndpointDTO::getName, this::getSharedInfo));
-	}
-
-	private Map<String, String> getSharedInfo(ProjectEndpointDTO endpointDTO) {
-		Optional<EdgeInfo> edgeInfo = Optional.ofNullable(endpointDTO.getEdgeInfo());
-		if (!edgeInfo.isPresent()) {
-			return Collections.emptyMap();
-		}
-		EdgeInfo edge = edgeInfo.get();
-		Map<String, String> shared = new HashMap<>();
-
-		shared.put("status", endpointDTO.getStatus().toString());
-		shared.put("edge_node_ip", edge.getPublicIp());
-		if (edge instanceof EdgeInfoAws) {
-			EdgeInfoAws edgeInfoAws = (EdgeInfoAws) edge;
-			shared.put("user_own_bicket_name", edgeInfoAws.getUserOwnBucketName());
-			shared.put("shared_bucket_name", edgeInfoAws.getSharedBucketName());
-		} else if (edge instanceof EdgeInfoAzure) {
-			EdgeInfoAzure edgeInfoAzure = (EdgeInfoAzure) edge;
-			shared.put("user_container_name", edgeInfoAzure.getUserContainerName());
-			shared.put("shared_container_name", edgeInfoAzure.getSharedContainerName());
-			shared.put("user_storage_account_name", edgeInfoAzure.getUserStorageAccountName());
-			shared.put("shared_storage_account_name", edgeInfoAzure.getSharedStorageAccountName());
-			shared.put("datalake_name", edgeInfoAzure.getDataLakeName());
-			shared.put("datalake_user_directory_name", edgeInfoAzure.getDataLakeDirectoryName());
-			shared.put("datalake_shared_directory_name", edgeInfoAzure.getDataLakeSharedDirectoryName());
-		} else if (edge instanceof EdgeInfoGcp) {
-			EdgeInfoGcp edgeInfoGcp = (EdgeInfoGcp) edge;
-			shared.put("user_own_bucket_name", edgeInfoGcp.getUserOwnBucketName());
-			shared.put("shared_bucket_name", edgeInfoGcp.getSharedBucketName());
-		}
-
-		return shared;
-	}
-
-	private boolean checkAccess(UserInfo userInfo, String permission) {
-		return UserRoles.checkAccess(userInfo, RoleType.PAGE, permission, userInfo.getRoles());
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceImpl.java
deleted file mode 100644
index 03f093b..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceImpl.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.ProjectDAO;
-import com.epam.dlab.backendapi.dao.SettingsDAO;
-import com.epam.dlab.backendapi.dao.UserGroupDAO;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.resources.dto.SparkStandaloneConfiguration;
-import com.epam.dlab.backendapi.resources.dto.aws.AwsEmrConfiguration;
-import com.epam.dlab.backendapi.resources.dto.gcp.GcpDataprocConfiguration;
-import com.epam.dlab.backendapi.roles.RoleType;
-import com.epam.dlab.backendapi.roles.UserRoles;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.InfrastructureTemplateService;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.base.computational.FullComputationalTemplate;
-import com.epam.dlab.dto.imagemetadata.ComputationalMetadataDTO;
-import com.epam.dlab.dto.imagemetadata.ComputationalResourceShapeDto;
-import com.epam.dlab.dto.imagemetadata.ExploratoryMetadataDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.cloud.CloudProvider.AZURE;
-import static com.epam.dlab.rest.contracts.DockerAPI.DOCKER_COMPUTATIONAL;
-import static com.epam.dlab.rest.contracts.DockerAPI.DOCKER_EXPLORATORY;
-
-@Slf4j
-public class InfrastructureTemplateServiceImpl implements InfrastructureTemplateService {
-
-	@Inject
-	private SelfServiceApplicationConfiguration configuration;
-	@Inject
-	private SettingsDAO settingsDAO;
-	@Inject
-	private ProjectDAO projectDAO;
-	@Inject
-	private EndpointService endpointService;
-	@Inject
-	private UserGroupDAO userGroupDao;
-
-
-	@Inject
-	@Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
-	private RESTService provisioningService;
-
-	@Override
-	public List<ExploratoryMetadataDTO> getExploratoryTemplates(UserInfo user, String project, String endpoint) {
-
-		log.debug("Loading list of exploratory templates for user {} for project {}", user.getName(), project);
-		try {
-			EndpointDTO endpointDTO = endpointService.get(endpoint);
-			ExploratoryMetadataDTO[] array =
-					provisioningService.get(endpointDTO.getUrl() + DOCKER_EXPLORATORY,
-							user.getAccessToken(),
-							ExploratoryMetadataDTO[].class);
-
-			final Set<String> roles = userGroupDao.getUserGroups(user.getName());
-			return Arrays.stream(array)
-					.peek(e -> e.setImage(getSimpleImageName(e.getImage())))
-					.filter(e -> exploratoryGpuIssuesAzureFilter(e, endpointDTO.getCloudProvider()) &&
-							UserRoles.checkAccess(user, RoleType.EXPLORATORY, e.getImage(), roles))
-					.peek(e -> filterShapes(user, e.getExploratoryEnvironmentShapes(), RoleType.EXPLORATORY_SHAPES, roles))
-					.collect(Collectors.toList());
-
-		} catch (DlabException e) {
-			log.error("Could not load list of exploratory templates for user: {}", user.getName(), e);
-			throw e;
-		}
-	}
-
-	@Override
-	public List<FullComputationalTemplate> getComputationalTemplates(UserInfo user, String project, String endpoint) {
-
-		log.debug("Loading list of computational templates for user {}", user.getName());
-		try {
-			EndpointDTO endpointDTO = endpointService.get(endpoint);
-			ComputationalMetadataDTO[] array =
-					provisioningService.get(endpointDTO.getUrl() + DOCKER_COMPUTATIONAL,
-							user.getAccessToken(), ComputationalMetadataDTO[]
-									.class);
-
-			final Set<String> roles = userGroupDao.getUserGroups(user.getName());
-
-			return Arrays.stream(array)
-					.peek(e -> e.setImage(getSimpleImageName(e.getImage())))
-					.peek(e -> filterShapes(user, e.getComputationResourceShapes(), RoleType.COMPUTATIONAL_SHAPES, roles))
-					.filter(e -> UserRoles.checkAccess(user, RoleType.COMPUTATIONAL, e.getImage(), roles))
-					.map(comp -> fullComputationalTemplate(comp, endpointDTO.getCloudProvider()))
-					.collect(Collectors.toList());
-
-		} catch (DlabException e) {
-			log.error("Could not load list of computational templates for user: {}", user.getName(), e);
-			throw e;
-		}
-	}
-
-	/**
-	 * Removes shapes for which user does not have an access
-	 *
-	 * @param user              user
-	 * @param environmentShapes shape types
-	 * @param roleType
-	 * @param roles
-	 */
-	private void filterShapes(UserInfo user, Map<String, List<ComputationalResourceShapeDto>> environmentShapes,
-							  RoleType roleType, Set<String> roles) {
-		environmentShapes.forEach((k, v) -> v.removeIf(compResShapeDto ->
-				!UserRoles.checkAccess(user, roleType, compResShapeDto.getType(), roles))
-		);
-	}
-
-	/**
-	 * Temporary filter for creation of exploratory env due to Azure issues
-	 */
-	private boolean exploratoryGpuIssuesAzureFilter(ExploratoryMetadataDTO e, CloudProvider cloudProvider) {
-		return (!"redhat".equals(settingsDAO.getConfOsFamily()) || cloudProvider != AZURE) ||
-				!(e.getImage().endsWith("deeplearning") || e.getImage().endsWith("tensor"));
-	}
-
-	/**
-	 * Return the image name without suffix version.
-	 *
-	 * @param imageName the name of image.
-	 */
-	private String getSimpleImageName(String imageName) {
-		int separatorIndex = imageName.indexOf(':');
-		return (separatorIndex > 0 ? imageName.substring(0, separatorIndex) : imageName);
-	}
-
-	/**
-	 * Wraps metadata with limits
-	 *
-	 * @param metadataDTO   metadata
-	 * @param cloudProvider cloudProvider
-	 * @return wrapped object
-	 */
-
-	private FullComputationalTemplate fullComputationalTemplate(ComputationalMetadataDTO metadataDTO,
-																CloudProvider cloudProvider) {
-
-		DataEngineType dataEngineType = DataEngineType.fromDockerImageName(metadataDTO.getImage());
-
-		if (dataEngineType == DataEngineType.CLOUD_SERVICE) {
-			return getCloudFullComputationalTemplate(metadataDTO, cloudProvider);
-		} else if (dataEngineType == DataEngineType.SPARK_STANDALONE) {
-			return new SparkFullComputationalTemplate(metadataDTO,
-					SparkStandaloneConfiguration.builder()
-							.maxSparkInstanceCount(configuration.getMaxSparkInstanceCount())
-							.minSparkInstanceCount(configuration.getMinSparkInstanceCount())
-							.build());
-		} else {
-			throw new IllegalArgumentException("Unknown data engine " + dataEngineType);
-		}
-	}
-
-	protected FullComputationalTemplate getCloudFullComputationalTemplate(ComputationalMetadataDTO metadataDTO,
-																		CloudProvider cloudProvider) {
-		switch (cloudProvider) {
-			case AWS:
-				return new AwsFullComputationalTemplate(metadataDTO,
-						AwsEmrConfiguration.builder()
-								.minEmrInstanceCount(configuration.getMinEmrInstanceCount())
-								.maxEmrInstanceCount(configuration.getMaxEmrInstanceCount())
-								.maxEmrSpotInstanceBidPct(configuration.getMaxEmrSpotInstanceBidPct())
-								.minEmrSpotInstanceBidPct(configuration.getMinEmrSpotInstanceBidPct())
-								.build());
-			case GCP:
-				return new GcpFullComputationalTemplate(metadataDTO,
-						GcpDataprocConfiguration.builder()
-								.minInstanceCount(configuration.getMinInstanceCount())
-								.maxInstanceCount(configuration.getMaxInstanceCount())
-								.minDataprocPreemptibleInstanceCount(configuration.getMinDataprocPreemptibleCount())
-								.build());
-			case AZURE:
-				log.error("Dataengine service is not supported currently for {}", AZURE);
-				throw new UnsupportedOperationException("Dataengine service is not supported currently for " + AZURE);
-			default:
-				throw new UnsupportedOperationException("Dataengine service is not supported currently for " + cloudProvider);
-		}
-	}
-
-	private class AwsFullComputationalTemplate extends FullComputationalTemplate {
-		@JsonProperty("limits")
-		private AwsEmrConfiguration awsEmrConfiguration;
-
-		AwsFullComputationalTemplate(ComputationalMetadataDTO metadataDTO,
-									 AwsEmrConfiguration awsEmrConfiguration) {
-			super(metadataDTO);
-			this.awsEmrConfiguration = awsEmrConfiguration;
-		}
-	}
-
-	private class GcpFullComputationalTemplate extends FullComputationalTemplate {
-		@JsonProperty("limits")
-		private GcpDataprocConfiguration gcpDataprocConfiguration;
-
-		GcpFullComputationalTemplate(ComputationalMetadataDTO metadataDTO,
-									 GcpDataprocConfiguration gcpDataprocConfiguration) {
-			super(metadataDTO);
-			this.gcpDataprocConfiguration = gcpDataprocConfiguration;
-		}
-	}
-
-	private class SparkFullComputationalTemplate extends FullComputationalTemplate {
-		@JsonProperty("limits")
-		private SparkStandaloneConfiguration sparkStandaloneConfiguration;
-
-		SparkFullComputationalTemplate(ComputationalMetadataDTO metadataDTO,
-									   SparkStandaloneConfiguration sparkStandaloneConfiguration) {
-			super(metadataDTO);
-			this.sparkStandaloneConfiguration = sparkStandaloneConfiguration;
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/LibraryServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/LibraryServiceImpl.java
deleted file mode 100644
index 797d58d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/LibraryServiceImpl.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.annotation.Audit;
-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.BaseDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryLibDAO;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.NotebookTemplate;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.resources.dto.LibInfoRecord;
-import com.epam.dlab.backendapi.resources.dto.LibKey;
-import com.epam.dlab.backendapi.resources.dto.LibraryStatus;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.LibraryService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.LibraryGroups;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.dto.exploratory.LibInstallDTO;
-import com.epam.dlab.dto.exploratory.LibStatus;
-import com.epam.dlab.dto.exploratory.LibraryInstallDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.model.library.Library;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.ComputationalAPI;
-import com.epam.dlab.rest.contracts.ExploratoryAPI;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.bson.Document;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.INSTALL_LIBS;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.COMPUTE;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.NOTEBOOK;
-import static com.epam.dlab.backendapi.domain.NotebookTemplate.DEEP_LEARNING;
-import static com.epam.dlab.backendapi.domain.NotebookTemplate.JUPYTER;
-import static com.epam.dlab.backendapi.domain.NotebookTemplate.RSTUDIO;
-import static com.epam.dlab.backendapi.domain.NotebookTemplate.TENSOR;
-import static com.epam.dlab.backendapi.domain.NotebookTemplate.TENSOR_RSTUDIO;
-import static com.epam.dlab.backendapi.domain.NotebookTemplate.ZEPPELIN;
-import static com.epam.dlab.dto.LibraryGroups.GROUP_JAVA;
-import static com.epam.dlab.dto.LibraryGroups.GROUP_OS_PKG;
-import static com.epam.dlab.dto.LibraryGroups.GROUP_OTHERS;
-import static com.epam.dlab.dto.LibraryGroups.GROUP_PIP2;
-import static com.epam.dlab.dto.LibraryGroups.GROUP_PIP3;
-import static com.epam.dlab.dto.LibraryGroups.GROUP_R_PKG;
-
-
-@Slf4j
-@Singleton
-public class LibraryServiceImpl implements LibraryService {
-	private static final String COMPUTATIONAL_NOT_FOUND_MSG = "Computational with name %s was not found";
-	private static final String LIB_ALREADY_INSTALLED = "Library %s is already installing";
-
-	@Inject
-	private ExploratoryDAO exploratoryDAO;
-
-	@Inject
-	private ExploratoryLibDAO libraryDAO;
-
-	@Inject
-	private RequestBuilder requestBuilder;
-
-	@Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
-	@Inject
-	private RESTService provisioningService;
-
-	@Inject
-	private RequestId requestId;
-
-	@Inject
-	private EndpointService endpointService;
-
-
-	@Override
-	@SuppressWarnings("unchecked")
-	public List<Document> getLibs(String user, String project, String exploratoryName, String computationalName) {
-		if (StringUtils.isEmpty(computationalName)) {
-			return (List<Document>) libraryDAO.findExploratoryLibraries(user, project, exploratoryName)
-					.getOrDefault(ExploratoryLibDAO.EXPLORATORY_LIBS, new ArrayList<>());
-		} else {
-			Document document = (Document) libraryDAO.findComputationalLibraries(user, project,
-					exploratoryName, computationalName)
-					.getOrDefault(ExploratoryLibDAO.COMPUTATIONAL_LIBS, new Document());
-
-			return (List<Document>) document.getOrDefault(computationalName, new ArrayList<>());
-		}
-	}
-
-	@Override
-	@SuppressWarnings("unchecked")
-	public List<LibInfoRecord> getLibInfo(String user, String project, String exploratoryName) {
-		Document document = libraryDAO.findAllLibraries(user, project, exploratoryName);
-
-		Map<LibKey, List<LibraryStatus>> model = new LinkedHashMap<>();
-		if (document.get(ExploratoryLibDAO.EXPLORATORY_LIBS) != null) {
-			List<Document> exploratoryLibs = (List<Document>) document.get(ExploratoryLibDAO.EXPLORATORY_LIBS);
-			exploratoryLibs.forEach(e -> populateModel(exploratoryName, e, model, "notebook"));
-		}
-		if (document.get(ExploratoryLibDAO.COMPUTATIONAL_LIBS) != null) {
-			Document computationalLibs = getLibsOfActiveComputationalResources(document);
-			populateComputational(computationalLibs, model, "cluster");
-		}
-
-		LinkedList<LibInfoRecord> libInfoRecords = new LinkedList<>();
-		for (Map.Entry<LibKey, List<LibraryStatus>> entry : model.entrySet()) {
-			libInfoRecords.addFirst(new LibInfoRecord(entry.getKey(), entry.getValue()));
-		}
-
-		return libInfoRecords;
-	}
-
-	@Audit(action = INSTALL_LIBS, type = COMPUTE)
-	@Override
-	public String installComputationalLibs(@User UserInfo ui, @Project String project, String expName, @ResourceName String compName,
-	                                       List<LibInstallDTO> libs, @Info String auditInfo) {
-		final UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(ui.getName(), project, expName, compName);
-		EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
-		final String uuid = provisioningService.post(endpointDTO.getUrl() + ComputationalAPI.COMPUTATIONAL_LIB_INSTALL,
-				ui.getAccessToken(),
-				toComputationalLibraryInstallDto(ui, project, expName, compName, libs, userInstance, endpointDTO),
-				String.class);
-		requestId.put(ui.getName(), uuid);
-		return uuid;
-	}
-
-    @Audit(action = INSTALL_LIBS, type = NOTEBOOK)
-    @Override
-    public String installExploratoryLibs(@User UserInfo ui, @Project String project, @ResourceName String expName, List<LibInstallDTO> libs, @Info String auditInfo) {
-	    final UserInstanceDTO userInstance = exploratoryDAO.fetchRunningExploratoryFields(ui.getName(), project, expName);
-	    EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
-	    final String uuid = provisioningService.post(endpointDTO.getUrl() + ExploratoryAPI.EXPLORATORY_LIB_INSTALL,
-			    ui.getAccessToken(), toExploratoryLibraryInstallDto(ui, project, expName, libs, userInstance, endpointDTO),
-			    String.class);
-	    requestId.put(ui.getName(), uuid);
-	    return uuid;
-    }
-
-	@Override
-	public List<String> getExploratoryLibGroups(UserInfo userInfo, String projectName, String exploratoryName) {
-		UserInstanceDTO userInstanceDTO = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), projectName, exploratoryName);
-		final String templateName = userInstanceDTO.getTemplateName();
-		List<LibraryGroups> groups = new ArrayList<>(Arrays.asList(GROUP_PIP2, GROUP_PIP3, GROUP_OTHERS, GROUP_OS_PKG));
-
-		if (isTemplateGroup(templateName, Stream.of(JUPYTER, ZEPPELIN))) {
-			groups.addAll(Arrays.asList(GROUP_R_PKG, GROUP_JAVA));
-		}
-		if (isTemplateGroup(templateName, Stream.of(DEEP_LEARNING, TENSOR))) {
-			groups.add(GROUP_JAVA);
-		}
-		if (isTemplateGroup(templateName, Stream.of(RSTUDIO, TENSOR_RSTUDIO))) {
-			groups.add(GROUP_R_PKG);
-		}
-
-		return groups
-				.stream()
-				.map(LibraryGroups::toString)
-				.collect(Collectors.toList());
-	}
-
-	@Override
-	public List<String> getComputeLibGroups() {
-		return Stream.of(GROUP_PIP3, GROUP_OTHERS, GROUP_R_PKG, GROUP_OS_PKG, GROUP_JAVA)
-				.map(LibraryGroups::toString)
-				.collect(Collectors.toList());
-	}
-
-	private boolean isTemplateGroup(String templateName, Stream<NotebookTemplate> templateStream) {
-		return templateStream
-				.map(NotebookTemplate::getName)
-				.anyMatch(name -> name.equals(templateName));
-	}
-
-	private LibraryInstallDTO toExploratoryLibraryInstallDto(UserInfo userInfo, String project, String exploratoryName,
-	                                                         List<LibInstallDTO> libs, UserInstanceDTO userInstance, EndpointDTO endpointDTO) {
-		final List<LibInstallDTO> libsToInstall = libs.stream()
-				.map(lib -> toLibInstallDto(lib, libraryDAO.getLibrary(userInfo.getName(), project, exploratoryName,
-						lib.getGroup(), lib.getName())))
-				.peek(l -> libraryDAO.addLibrary(userInfo.getName(), project, exploratoryName, l, l.isOverride()))
-				.collect(Collectors.toList());
-		return requestBuilder.newLibInstall(userInfo, userInstance, endpointDTO, libsToInstall);
-	}
-
-	private LibraryInstallDTO toComputationalLibraryInstallDto(UserInfo userInfo, String project, String expName,
-															   String compName, List<LibInstallDTO> libs,
-															   UserInstanceDTO userInstance, EndpointDTO endpointDTO) {
-
-		final UserComputationalResource computationalResource = getComputationalResource(compName, userInstance);
-		final List<LibInstallDTO> libsToInstall = libs.stream()
-				.map(lib -> toLibInstallDto(lib, libraryDAO.getLibrary(userInfo.getName(), project,
-						expName, compName, lib.getGroup(), lib.getName())))
-				.peek(l -> libraryDAO.addLibrary(userInfo.getName(), project, expName, compName,
-						l, l.isOverride()))
-				.collect(Collectors.toList());
-		return requestBuilder.newLibInstall(userInfo, userInstance, computationalResource, libsToInstall, endpointDTO);
-	}
-
-	private UserComputationalResource getComputationalResource(String computationalName,
-															   UserInstanceDTO userInstance) {
-		return userInstance.getResources()
-				.stream()
-				.filter(computational -> computational.getComputationalName().equals(computationalName))
-				.findAny()
-				.orElseThrow(() -> new DlabException(String.format(COMPUTATIONAL_NOT_FOUND_MSG, computationalName)));
-	}
-
-	private LibInstallDTO toLibInstallDto(LibInstallDTO lib, Library existingLibrary) {
-		final LibInstallDTO l = new LibInstallDTO(lib.getGroup(), lib.getName(), lib.getVersion());
-		l.setStatus(LibStatus.INSTALLING.toString());
-		l.setOverride(shouldOverride(existingLibrary));
-		return l;
-	}
-
-	private boolean shouldOverride(Library library) {
-		if (Objects.nonNull(library) && library.getStatus() == LibStatus.INSTALLING) {
-			throw new DlabException(String.format(LIB_ALREADY_INSTALLED, library.getName()));
-		} else {
-			return Objects.nonNull(library);
-		}
-	}
-
-	@SuppressWarnings("unchecked")
-	private Document getLibsOfActiveComputationalResources(Document document) {
-		Document computationalLibs = (Document) document.get(ExploratoryLibDAO.COMPUTATIONAL_LIBS);
-
-		if (document.get(ExploratoryDAO.COMPUTATIONAL_RESOURCES) != null) {
-			List<Document> computationalResources = (List<Document>) document.get(ExploratoryDAO
-					.COMPUTATIONAL_RESOURCES);
-
-			Set<String> terminated = computationalResources.stream()
-					.filter(doc -> doc.getString(BaseDAO.STATUS).equalsIgnoreCase(UserInstanceStatus.TERMINATED
-							.toString()))
-					.map(doc -> doc.getString("computational_name")).collect(Collectors.toSet());
-
-			terminated.forEach(computationalLibs::remove);
-		}
-
-		return computationalLibs;
-	}
-
-
-	private void populateModel(String exploratoryName, Document document, Map<LibKey, List<LibraryStatus>> model,
-							   String resourceType) {
-		String name = document.getString(ExploratoryLibDAO.LIB_NAME);
-		String version = document.getString(ExploratoryLibDAO.LIB_VERSION);
-		String group = document.getString(ExploratoryLibDAO.LIB_GROUP);
-		String status = document.getString(ExploratoryLibDAO.STATUS);
-		List<String> availableVersions = (List<String>) document.get(ExploratoryLibDAO.LIB_AVAILABLE_VERSION);
-		List<String> addedPackages = (List<String>) document.get(ExploratoryLibDAO.LIB_ADDED_PACKAGES);
-		String error = document.getString(ExploratoryLibDAO.ERROR_MESSAGE);
-
-		LibKey libKey = new LibKey(name, version, group);
-		List<LibraryStatus> statuses = model.getOrDefault(libKey, new ArrayList<>());
-
-		if (statuses.isEmpty()) {
-			model.put(libKey, statuses);
-		}
-
-		statuses.add(new LibraryStatus(exploratoryName, resourceType, status, error, availableVersions, addedPackages));
-	}
-
-	@SuppressWarnings("unchecked")
-	private void populateComputational(Document computationalLibs, Map<LibKey, List<LibraryStatus>> model, String
-			resourceType) {
-		for (Map.Entry<String, Object> entry : computationalLibs.entrySet()) {
-			if (entry.getValue() != null) {
-				List<Document> docs = (List<Document>) entry.getValue();
-				docs.forEach(e -> populateModel(entry.getKey(), e, model, resourceType));
-			}
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/MavenCentralLibraryService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/MavenCentralLibraryService.java
deleted file mode 100644
index 13d0c86..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/MavenCentralLibraryService.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.domain.MavenSearchArtifactResponse;
-import com.epam.dlab.backendapi.resources.dto.LibraryDTO;
-import com.epam.dlab.backendapi.service.ExternalLibraryService;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.inject.Inject;
-import java.net.URI;
-
-import static java.lang.String.join;
-
-@Singleton
-@Slf4j
-public class MavenCentralLibraryService implements ExternalLibraryService {
-
-	private static final String QUOTE_ENCODED = "%22";
-	private static final String SEARCH_API_QUERY_FORMAT = "/solrsearch/select?q=%s&rows=20&wt=json&core=gav&p=jar";
-	private static final String LIB_NOT_FOUND_MSG = "No matches found";
-	private final RESTService restClient;
-
-	@Inject
-	public MavenCentralLibraryService(@Named(ServiceConsts.MAVEN_SEARCH_API) RESTService restClient) {
-		this.restClient = restClient;
-	}
-
-	@Override
-	public LibraryDTO getLibrary(String groupId, String artifactId, String version) {
-		return getMavenLibrary(groupId, artifactId, version);
-
-	}
-
-	private LibraryDTO getMavenLibrary(String groupId, String artifactId, String version) {
-		final String query = and(artifactQuery(artifactId), groupQuery(groupId), versionQuery(version), jarOrBundlePackage());
-		return restClient.get(URI.create(String.format(SEARCH_API_QUERY_FORMAT, query)),
-				MavenSearchArtifactResponse.class)
-				.getArtifacts()
-				.stream()
-				.findFirst()
-				.map(artifact -> new LibraryDTO(join(":", groupId, artifactId), version))
-				.orElseThrow(() -> new ResourceNotFoundException(LIB_NOT_FOUND_MSG));
-	}
-
-	private String groupQuery(String groupId) {
-		return "g:" + QUOTE_ENCODED + groupId + QUOTE_ENCODED;
-	}
-
-	private String artifactQuery(String artifactId) {
-		return "a:" + QUOTE_ENCODED + artifactId + QUOTE_ENCODED;
-	}
-
-	private String versionQuery(String version) {
-		return "v:" + QUOTE_ENCODED + version + QUOTE_ENCODED;
-	}
-
-	private String jarOrBundlePackage() {
-		return "(p:" + QUOTE_ENCODED + "jar" + QUOTE_ENCODED + "%20OR%20p:" + QUOTE_ENCODED + "bundle" + QUOTE_ENCODED + ")";
-	}
-
-	private String and(String... strings) {
-		return join("+AND+", strings);
-	}
-
-}
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
deleted file mode 100644
index 7e902fc..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * 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.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;
-import com.epam.dlab.backendapi.domain.BudgetDTO;
-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.util.RequestBuilder;
-import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.exceptions.ResourceConflictException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.CREATE;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.START;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.STOP;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.TERMINATE;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.UPDATE;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.EDGE_NODE;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.PROJECT;
-import static java.util.stream.Collectors.toSet;
-import static java.util.stream.Stream.concat;
-
-@Slf4j
-public class ProjectServiceImpl implements ProjectService {
-
-	private static final String CREATE_PRJ_API = "infrastructure/project/create";
-	private static final String TERMINATE_PRJ_API = "infrastructure/project/terminate";
-	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 TOTAL_BUDGET_PERIOD = "Total";
-	private static final String MONTHLY_BUDGET_PERIOD = "Monthly";
-
-	private static final String AUDIT_ADD_ENDPOINT = "Add endpoint(s): %s\n";
-	private static final String AUDIT_ADD_GROUP = "Add group(s): %s\n";
-	private static final String AUDIT_REMOVE_GROUP = "Remove group(s): %s\n";
-	private static final String AUDIT_UPDATE_BUDGET = "Update quota: %d->%d\nUpdate period: %s->%s";
-	private static final String AUDIT_ADD_EDGE_NODE = "Create edge node for endpoint %s, requested in project %s";
-
-	private final ProjectDAO projectDAO;
-	private final ExploratoryService exploratoryService;
-	private final UserGroupDAO userGroupDao;
-	private final RESTService provisioningService;
-	private final RequestId requestId;
-	private final RequestBuilder requestBuilder;
-	private final EndpointService endpointService;
-	private final ExploratoryDAO exploratoryDAO;
-	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, SelfServiceApplicationConfiguration configuration) {
-		this.projectDAO = projectDAO;
-		this.exploratoryService = exploratoryService;
-		this.userGroupDao = userGroupDao;
-		this.provisioningService = provisioningService;
-		this.requestId = requestId;
-		this.requestBuilder = requestBuilder;
-		this.endpointService = endpointService;
-		this.exploratoryDAO = exploratoryDAO;
-		this.configuration = configuration;
-	}
-
-	@Override
-	public List<ProjectDTO> getProjects() {
-		return projectDAO.getProjects();
-	}
-
-	@Override
-	public List<ProjectDTO> getProjects(UserInfo user) {
-		return projectDAO.getProjects()
-				.stream()
-				.filter(project -> UserRoles.isProjectAdmin(user, project.getGroups()) || UserRoles.isAdmin(user))
-				.collect(Collectors.toList());
-	}
-
-	@Override
-	public List<ProjectDTO> getUserProjects(UserInfo userInfo, boolean active) {
-		return projectDAO.getUserProjects(userInfo, active);
-	}
-
-	@Override
-	public List<ProjectDTO> getProjectsByEndpoint(String endpointName) {
-		return projectDAO.getProjectsByEndpoint(endpointName);
-	}
-
-	@BudgetLimited
-	@Override
-	public void create(UserInfo user, ProjectDTO projectDTO, String resourceName) {
-		if (!projectDAO.get(projectDTO.getName()).isPresent()) {
-			projectDAO.create(projectDTO);
-			createProjectOnCloud(user, projectDTO);
-		} else {
-			throw new ResourceConflictException("Project with passed name already exist in system");
-		}
-	}
-
-	@Override
-	public ProjectDTO get(String name) {
-		return projectDAO.get(name)
-				.orElseThrow(projectNotFound());
-	}
-
-	@Audit(action = TERMINATE, type = EDGE_NODE)
-	@Override
-	public void terminateEndpoint(@User UserInfo userInfo, @ResourceName String endpoint, @Project String name) {
-		projectActionOnCloud(userInfo, name, TERMINATE_PRJ_API, endpoint);
-		projectDAO.updateEdgeStatus(name, endpoint, UserInstanceStatus.TERMINATING);
-		exploratoryService.updateProjectExploratoryStatuses(userInfo, name, endpoint, UserInstanceStatus.TERMINATING);
-	}
-
-	@ProjectAdmin
-	@Override
-	public void terminateEndpoint(@User UserInfo userInfo, List<String> endpoints, @Project String name) {
-		List<ProjectEndpointDTO> endpointDTOs = getProjectEndpointDTOS(endpoints, name);
-		checkProjectRelatedResourcesInProgress(name, endpointDTOs, TERMINATE_ACTION);
-		endpoints.forEach(endpoint -> terminateEndpoint(userInfo, endpoint, name));
-	}
-
-	@BudgetLimited
-	@Audit(action = START, type = EDGE_NODE)
-	@Override
-	public void start(@User UserInfo userInfo,@ResourceName String endpoint, @Project String name) {
-		projectActionOnCloud(userInfo, name, START_PRJ_API, endpoint);
-		projectDAO.updateEdgeStatus(name, endpoint, UserInstanceStatus.STARTING);
-	}
-
-	@ProjectAdmin
-	@Override
-	public void start(@User UserInfo userInfo, List<String> endpoints, @Project String name) {
-		endpoints.forEach(endpoint -> start(userInfo, endpoint, name));
-	}
-
-	@Audit(action = STOP, type = EDGE_NODE)
-	@Override
-	public void stop(@User UserInfo userInfo, @ResourceName String endpoint,@Project String name, @Info String auditInfo) {
-		projectActionOnCloud(userInfo, name, STOP_PRJ_API, endpoint);
-		projectDAO.updateEdgeStatus(name, endpoint, UserInstanceStatus.STOPPING);
-	}
-
-	@ProjectAdmin
-	@Override
-	public void stopWithResources(@User UserInfo userInfo, List<String> endpoints, @ResourceName @Project String projectName) {
-		List<ProjectEndpointDTO> endpointDTOs = getProjectEndpointDTOS(endpoints, projectName);
-		checkProjectRelatedResourcesInProgress(projectName, endpointDTOs, STOP_ACTION);
-
-		endpointDTOs
-				.stream()
-				.filter(e -> !Arrays.asList(UserInstanceStatus.TERMINATED, UserInstanceStatus.TERMINATING, UserInstanceStatus.STOPPED,
-						UserInstanceStatus.FAILED).contains(e.getStatus()))
-				.forEach(e -> stop(userInfo, e.getName(), projectName, null));
-
-		exploratoryDAO.fetchRunningExploratoryFieldsForProject(projectName,
-				endpointDTOs
-						.stream()
-						.map(ProjectEndpointDTO::getName)
-						.collect(Collectors.toList()))
-				.forEach(e -> exploratoryService.stop(userInfo, e.getUser(), projectName, e.getExploratoryName(), null));
-	}
-
-	@ProjectAdmin
-	@Override
-	public void update(@User UserInfo userInfo, UpdateProjectDTO projectDTO, @Project String projectName) {
-		final ProjectDTO project = projectDAO.get(projectDTO.getName()).orElseThrow(projectNotFound());
-		final Set<String> endpoints = project.getEndpoints()
-				.stream()
-				.map(ProjectEndpointDTO::getName)
-				.collect(toSet());
-		final Set<String> newEndpoints = new HashSet<>(projectDTO.getEndpoints());
-		newEndpoints.removeAll(endpoints);
-		final String projectUpdateAudit = updateProjectAudit(projectDTO, project, newEndpoints);
-		updateProject(userInfo, projectName, projectDTO, project, newEndpoints, projectUpdateAudit);
-	}
-
-	@Audit(action = UPDATE, type = PROJECT)
-	public void updateProject(@User UserInfo userInfo, @Project @ResourceName String projectName, UpdateProjectDTO projectDTO, ProjectDTO project, Set<String> newEndpoints,
-	                          @Info String projectAudit) {
-		final List<ProjectEndpointDTO> endpointsToBeCreated = newEndpoints
-				.stream()
-				.map(e -> new ProjectEndpointDTO(e, UserInstanceStatus.CREATING, null))
-				.collect(Collectors.toList());
-		project.getEndpoints().addAll(endpointsToBeCreated);
-		projectDAO.update(new ProjectDTO(project.getName(), projectDTO.getGroups(), project.getKey(),
-				project.getTag(), project.getBudget(), project.getEndpoints(), projectDTO.isSharedImageEnabled()));
-		endpointsToBeCreated.forEach(e -> createEndpoint(userInfo, projectName, project, e.getName(), String.format(AUDIT_ADD_EDGE_NODE, e.getName(), project.getName())));
-	}
-
-	@Override
-	public void updateBudget(UserInfo userInfo, List<UpdateProjectBudgetDTO> dtos) {
-		final List<ProjectDTO> projects = dtos
-				.stream()
-				.map(this::getUpdateProjectDTO)
-				.collect(Collectors.toList());
-
-		projects.forEach(p -> updateBudget(userInfo, p.getName(), p.getBudget(), getUpdateBudgetAudit(p)));
-	}
-
-	@Audit(action = UPDATE, type = PROJECT)
-	public void updateBudget(@User UserInfo userInfo, @Project @ResourceName String name, BudgetDTO budget, @Info String updateBudgetAudit) {
-		projectDAO.updateBudget(name, budget.getValue(), budget.isMonthlyBudget());
-	}
-
-	@Override
-	public boolean isAnyProjectAssigned(UserInfo userInfo) {
-		final Set<String> userGroups = concat(userInfo.getRoles().stream(),
-				userGroupDao.getUserGroups(userInfo.getName()).stream())
-				.collect(toSet());
-		return projectDAO.isAnyProjectAssigned(userGroups);
-	}
-
-	@Override
-	public boolean checkExploratoriesAndComputationalProgress(String projectName, List<String> endpoints) {
-		return exploratoryDAO.fetchProjectEndpointExploratoriesWhereStatusIn(projectName, endpoints, Arrays.asList(
-				UserInstanceStatus.CREATING, UserInstanceStatus.STARTING, UserInstanceStatus.CREATING_IMAGE,
-				UserInstanceStatus.CONFIGURING, UserInstanceStatus.RECONFIGURING, UserInstanceStatus.STOPPING,
-				UserInstanceStatus.TERMINATING),
-				UserInstanceStatus.CREATING, UserInstanceStatus.CONFIGURING, UserInstanceStatus.STARTING,
-				UserInstanceStatus.RECONFIGURING, UserInstanceStatus.CREATING_IMAGE, UserInstanceStatus.STOPPING,
-				UserInstanceStatus.TERMINATING).isEmpty();
-	}
-
-	private void createProjectOnCloud(UserInfo user, ProjectDTO project) {
-		try {
-			project.getEndpoints().forEach(e -> createEndpoint(user, project.getName(), project, e.getName(), String.format(AUDIT_ADD_EDGE_NODE, e.getName(), project.getName())));
-		} catch (Exception e) {
-			log.error("Can not create project due to: {}", e.getMessage(), e);
-			projectDAO.updateStatus(project.getName(), ProjectDTO.Status.FAILED);
-		}
-	}
-
-	@Audit(action = CREATE, type = EDGE_NODE)
-	public void createEndpoint(@User UserInfo user, @Project String projectName, ProjectDTO projectDTO, @ResourceName String endpointName, @Info String auditInfo) {
-		EndpointDTO endpointDTO = endpointService.get(endpointName);
-		String uuid = provisioningService.post(endpointDTO.getUrl() + CREATE_PRJ_API, user.getAccessToken(),
-				requestBuilder.newProjectCreate(user, projectDTO, endpointDTO), String.class);
-		requestId.put(user.getName(), uuid);
-	}
-
-	private void projectActionOnCloud(UserInfo user, String projectName, String provisioningApiUri, String endpoint) {
-		try {
-			EndpointDTO endpointDTO = endpointService.get(endpoint);
-			String uuid = provisioningService.post(endpointDTO.getUrl() + provisioningApiUri, user.getAccessToken(),
-					requestBuilder.newProjectAction(user, projectName, endpointDTO), String.class);
-			requestId.put(user.getName(), uuid);
-		} catch (Exception e) {
-			log.error("Can not terminate project due to: {}", e.getMessage(), e);
-			projectDAO.updateStatus(projectName, ProjectDTO.Status.FAILED);
-		}
-	}
-
-	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()));
-
-		List<String> endpointNames = endpoints
-				.stream()
-				.map(ProjectEndpointDTO::getName)
-				.collect(Collectors.toList());
-		if (edgeProgress || !checkExploratoriesAndComputationalProgress(projectName, endpointNames)) {
-			throw new ResourceConflictException((String.format("Can not %s environment because one of project " +
-					"resource is in processing stage", action)));
-		}
-	}
-
-	private String updateProjectAudit(UpdateProjectDTO projectDTO, ProjectDTO project, Set<String> newEndpoints) {
-		if (!configuration.isAuditEnabled()) {
-			return null;
-		}
-		StringBuilder audit = new StringBuilder();
-		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.append(String.format(AUDIT_ADD_ENDPOINT, String.join(", ", newEndpoints)));
-		}
-		if (!newGroups.isEmpty()) {
-			audit.append(String.format(AUDIT_ADD_GROUP, String.join(", ", newGroups)));
-		}
-		if (!removedGroups.isEmpty()) {
-			audit.append(String.format(AUDIT_REMOVE_GROUP, String.join(", ", removedGroups)));
-		}
-		return audit.toString();
-	}
-
-	private String getUpdateBudgetAudit(ProjectDTO p) {
-		if (!configuration.isAuditEnabled()) {
-			return null;
-		}
-		ProjectDTO projectDTO = get(p.getName());
-		Integer value = Optional.ofNullable(projectDTO.getBudget())
-				.map(BudgetDTO::getValue)
-				.orElse(null);
-		Boolean monthlyBudget = Optional.ofNullable(projectDTO.getBudget())
-				.map(BudgetDTO::isMonthlyBudget)
-				.orElse(null);
-		return String.format(AUDIT_UPDATE_BUDGET, value, p.getBudget().getValue(),
-				representBudgetType(monthlyBudget), representBudgetType(p.getBudget().isMonthlyBudget()));
-	}
-
-    private String representBudgetType(Boolean isMonthlyPeriod) {
-		return (isMonthlyPeriod) ? MONTHLY_BUDGET_PERIOD : TOTAL_BUDGET_PERIOD;
-	}
-
-	private List<ProjectEndpointDTO> getProjectEndpointDTOS(List<String> endpoints, @Project String name) {
-		return get(name)
-				.getEndpoints()
-				.stream()
-				.filter(projectEndpointDTO -> endpoints.contains(projectEndpointDTO.getName()))
-				.collect(Collectors.toList());
-	}
-
-	private ProjectDTO getUpdateProjectDTO(UpdateProjectBudgetDTO dto) {
-		BudgetDTO budgetDTO = BudgetDTO.builder()
-				.value(dto.getBudget())
-				.monthlyBudget(dto.isMonthlyBudget())
-				.build();
-		return ProjectDTO.builder()
-				.name(dto.getProject())
-				.budget(budgetDTO)
-				.build();
-	}
-
-	private Supplier<ResourceNotFoundException> projectNotFound() {
-		return () -> new ResourceNotFoundException("Project with passed name not found");
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ReuploadKeyServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ReuploadKeyServiceImpl.java
deleted file mode 100644
index e75d9df..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ReuploadKeyServiceImpl.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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.ComputationalDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.ExploratoryService;
-import com.epam.dlab.backendapi.service.ReuploadKeyService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyStatus;
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyStatusDTO;
-import com.epam.dlab.model.ResourceData;
-import com.epam.dlab.model.ResourceType;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-
-import static com.epam.dlab.constants.ServiceConsts.PROVISIONING_SERVICE_NAME;
-import static com.epam.dlab.dto.UserInstanceStatus.RUNNING;
-
-@Singleton
-@Slf4j
-public class ReuploadKeyServiceImpl implements ReuploadKeyService {
-
-	@Inject
-	@Named(PROVISIONING_SERVICE_NAME)
-	private RESTService provisioningService;
-	@Inject
-	private RequestBuilder requestBuilder;
-	@Inject
-	private RequestId requestId;
-	@Inject
-	private ExploratoryService exploratoryService;
-	@Inject
-	private ComputationalDAO computationalDAO;
-	@Inject
-	private ExploratoryDAO exploratoryDAO;
-
-	private static final String REUPLOAD_KEY_UPDATE_MSG = "Reuploading key process is successfully finished. " +
-			"Updating 'reupload_key_required' flag to 'false' for {}.";
-	private static final String REUPLOAD_KEY_ERROR_MSG = "Reuploading key process is failed for {}. The next attempt" +
-			"starts after resource restarting.";
-
-	@Override
-	public void updateResourceData(ReuploadKeyStatusDTO dto) {
-        String user = dto.getUser();
-        ResourceData resource = dto.getReuploadKeyCallbackDTO().getResource();
-        log.debug("Updating resource {} to status RUNNING...", resource.toString());
-        updateResourceStatus(user, null, resource, RUNNING);
-        if (dto.getReuploadKeyStatus() == ReuploadKeyStatus.COMPLETED) {
-            log.debug(REUPLOAD_KEY_UPDATE_MSG, resource.toString());
-            updateResourceReuploadKeyFlag(user, null, resource, false);
-        } else {
-            log.error(REUPLOAD_KEY_ERROR_MSG, resource.toString());
-        }
-    }
-
-    private void updateResourceStatus(String user, String project, ResourceData resourceData, UserInstanceStatus newStatus) {
-        if (resourceData.getResourceType() == ResourceType.EXPLORATORY) {
-            exploratoryDAO.updateStatusForExploratory(user, project, resourceData.getExploratoryName(), newStatus);
-        } else if (resourceData.getResourceType() == ResourceType.COMPUTATIONAL) {
-            computationalDAO.updateStatusForComputationalResource(user, project,
-                    resourceData.getExploratoryName(), resourceData.getComputationalName(), newStatus);
-        }
-    }
-
-    private void updateResourceReuploadKeyFlag(String user, String project, ResourceData resourceData, boolean reuploadKeyRequired) {
-        if (resourceData.getResourceType() == ResourceType.EXPLORATORY) {
-            exploratoryDAO.updateReuploadKeyForExploratory(user, project, resourceData.getExploratoryName(), reuploadKeyRequired);
-        } else if (resourceData.getResourceType() == ResourceType.COMPUTATIONAL) {
-            computationalDAO.updateReuploadKeyFlagForComputationalResource(user, project,
-                    resourceData.getExploratoryName(), resourceData.getComputationalName(), reuploadKeyRequired);
-        }
-    }
-}
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
deleted file mode 100644
index a929698..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImpl.java
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.annotation.Audit;
-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.EnvDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.SchedulerJobDAO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.ComputationalService;
-import com.epam.dlab.backendapi.service.ExploratoryService;
-import com.epam.dlab.backendapi.service.SchedulerJobService;
-import com.epam.dlab.backendapi.service.SecurityService;
-import com.epam.dlab.dto.SchedulerJobDTO;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.exceptions.ResourceInappropriateStateException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.model.scheduler.SchedulerJobData;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-
-import java.time.DayOfWeek;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.OffsetDateTime;
-import java.time.ZoneOffset;
-import java.time.temporal.ChronoUnit;
-import java.util.Date;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.SET_UP_SCHEDULER;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.COMPUTE;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.NOTEBOOK;
-import static com.epam.dlab.constants.ServiceConsts.PROVISIONING_SERVICE_NAME;
-import static com.epam.dlab.dto.UserInstanceStatus.CONFIGURING;
-import static com.epam.dlab.dto.UserInstanceStatus.CREATING;
-import static com.epam.dlab.dto.UserInstanceStatus.RUNNING;
-import static com.epam.dlab.dto.UserInstanceStatus.STARTING;
-import static com.epam.dlab.dto.UserInstanceStatus.STOPPED;
-import static com.epam.dlab.dto.UserInstanceStatus.STOPPING;
-import static com.epam.dlab.dto.UserInstanceStatus.TERMINATING;
-import static com.epam.dlab.dto.base.DataEngineType.getDockerImageName;
-import static java.time.ZoneId.systemDefault;
-import static java.util.Collections.singletonList;
-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 AUDIT_MESSAGE = "Scheduled action, requested for notebook %s";
-	private static final long ALLOWED_INACTIVITY_MINUTES = 1L;
-
-	@Inject
-	private SchedulerJobDAO schedulerJobDAO;
-
-	@Inject
-	private ExploratoryDAO exploratoryDAO;
-
-	@Inject
-	private ComputationalDAO computationalDAO;
-
-	@Inject
-	private ExploratoryService exploratoryService;
-
-	@Inject
-	private ComputationalService computationalService;
-
-	@Inject
-	private SecurityService securityService;
-
-	@Inject
-	private EnvDAO envDAO;
-
-	@Inject
-	private RequestId requestId;
-
-	@Inject
-    @Named(PROVISIONING_SERVICE_NAME)
-    private RESTService provisioningService;
-
-    @Override
-    public SchedulerJobDTO fetchSchedulerJobForUserAndExploratory(String user, String project, String exploratoryName) {
-        return schedulerJobDAO.fetchSingleSchedulerJobByUserAndExploratory(user, project, exploratoryName)
-                .orElseThrow(() -> new ResourceNotFoundException(String.format(SCHEDULER_NOT_FOUND_MSG, user,
-                        exploratoryName)));
-    }
-
-    @Override
-    public SchedulerJobDTO fetchSchedulerJobForComputationalResource(String user, String project, String exploratoryName,
-                                                                     String computationalName) {
-        return schedulerJobDAO.fetchSingleSchedulerJobForCluster(user, project, exploratoryName, computationalName)
-                .orElseThrow(() -> new ResourceNotFoundException(String.format(SCHEDULER_NOT_FOUND_MSG, user,
-                        exploratoryName) + " with computational resource " + computationalName));
-    }
-
-	@Audit(action = SET_UP_SCHEDULER, type = NOTEBOOK)
-	@Override
-    public void updateExploratorySchedulerData(@User UserInfo user, @Project String project, @ResourceName String exploratoryName, SchedulerJobDTO dto) {
-        validateExploratoryStatus(user.getName(), project, exploratoryName);
-        populateDefaultSchedulerValues(dto);
-        log.debug("Updating exploratory {} for user {} with new scheduler job data: {}...", exploratoryName, user,
-                dto);
-        exploratoryDAO.updateSchedulerDataForUserAndExploratory(user.getName(), project, exploratoryName, dto);
-
-        if (!dto.inactivityScheduler() && dto.isSyncStartRequired()) {
-            shareSchedulerJobDataToSparkClusters(user.getName(), project, exploratoryName, dto);
-        } else if (!dto.inactivityScheduler()) {
-            computationalDAO.updateSchedulerSyncFlag(user.getName(), project, exploratoryName, dto.isSyncStartRequired());
-        }
-    }
-
-	@Audit(action = SET_UP_SCHEDULER, type = COMPUTE)
-	@Override
-    public void updateComputationalSchedulerData(@User UserInfo user, @Project String project, String exploratoryName, @ResourceName String computationalName, SchedulerJobDTO dto) {
-        validateExploratoryStatus(user.getName(), project, exploratoryName);
-        validateComputationalStatus(user.getName(), project, exploratoryName, computationalName);
-        populateDefaultSchedulerValues(dto);
-        log.debug("Updating computational resource {} affiliated with exploratory {} for user {} with new scheduler " +
-                "job data {}...", computationalName, exploratoryName, user, dto);
-        computationalDAO.updateSchedulerDataForComputationalResource(user.getName(), project, exploratoryName, computationalName, dto);
-    }
-
-    @Override
-    public void stopComputationalByScheduler() {
-        getComputationalSchedulersForStopping(OffsetDateTime.now(), true)
-                .forEach(this::stopComputational);
-    }
-
-    @Override
-    public void stopExploratoryByScheduler() {
-        getExploratorySchedulersForStopping(OffsetDateTime.now(), true)
-				.forEach(this::stopExploratory);
-	}
-
-	@Override
-	public void startExploratoryByScheduler() {
-		getExploratorySchedulersForStarting(OffsetDateTime.now())
-				.forEach(this::startExploratory);
-	}
-
-	@Override
-	public void startComputationalByScheduler() {
-		getComputationalSchedulersForStarting(OffsetDateTime.now())
-				.forEach(job -> startSpark(job.getUser(), job.getExploratoryName(), job.getComputationalName(),
-						job.getProject()));
-	}
-
-	@Override
-	public void terminateExploratoryByScheduler() {
-		getExploratorySchedulersForTerminating(OffsetDateTime.now())
-				.forEach(this::terminateExploratory);
-
-	}
-
-	@Override
-	public void terminateComputationalByScheduler() {
-		getComputationalSchedulersForTerminating(OffsetDateTime.now()).forEach(this::terminateComputational);
-
-	}
-
-	@Override
-	public void removeScheduler(String user, String exploratoryName) {
-		schedulerJobDAO.removeScheduler(user, exploratoryName);
-	}
-
-	@Override
-	public void removeScheduler(String user, String exploratoryName, String computationalName) {
-		schedulerJobDAO.removeScheduler(user, exploratoryName, computationalName);
-	}
-
-	@Override
-	public List<SchedulerJobData> getActiveSchedulers(String user, long minutesOffset) {
-		final OffsetDateTime desiredDateTime = OffsetDateTime.now().plusMinutes(minutesOffset);
-		final Predicate<SchedulerJobData> userPredicate = s -> user.equals(s.getUser());
-		final Stream<SchedulerJobData> computationalSchedulersStream =
-				getComputationalSchedulersForStopping(desiredDateTime)
-						.stream()
-						.filter(userPredicate);
-		final Stream<SchedulerJobData> exploratorySchedulersStream =
-				getExploratorySchedulersForStopping(desiredDateTime)
-						.stream()
-						.filter(userPredicate);
-		return Stream.concat(computationalSchedulersStream, exploratorySchedulersStream)
-				.collect(Collectors.toList());
-	}
-
-	private void stopComputational(SchedulerJobData job) {
-        final String project = job.getProject();
-        final String expName = job.getExploratoryName();
-        final String compName = job.getComputationalName();
-        final String user = job.getUser();
-		log.debug("Stopping exploratory {} computational {} for user {} by scheduler", expName, compName, user);
-		computationalService.stopSparkCluster(securityService.getServiceAccountInfo(user), user, project, expName, compName, String.format(AUDIT_MESSAGE, expName));
-    }
-
-	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, user, job.getProject(), expName, compName, String.format(AUDIT_MESSAGE, expName));
-    }
-
-	private void stopExploratory(SchedulerJobData job) {
-        final String expName = job.getExploratoryName();
-        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), user, project, expName, String.format(AUDIT_MESSAGE, expName));
-    }
-
-	private List<SchedulerJobData> getExploratorySchedulersForTerminating(OffsetDateTime now) {
-		return schedulerJobDAO.getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED)
-				.stream()
-				.filter(canSchedulerForTerminatingBeApplied(now))
-				.collect(Collectors.toList());
-	}
-
-	private List<SchedulerJobData> getComputationalSchedulersForTerminating(OffsetDateTime now) {
-		return schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(RUNNING, STOPPED, RUNNING)
-				.stream()
-				.filter(canSchedulerForTerminatingBeApplied(now))
-				.collect(Collectors.toList());
-	}
-
-	private void startExploratory(SchedulerJobData schedulerJobData) {
-        final String user = schedulerJobData.getUser();
-        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, String.format(AUDIT_MESSAGE, exploratoryName));
-        if (schedulerJobData.getJobDTO().isSyncStartRequired()) {
-            log.trace("Starting computational for exploratory {} for user {} by scheduler", exploratoryName, user);
-            final DataEngineType sparkCluster = DataEngineType.SPARK_STANDALONE;
-            final List<UserComputationalResource> compToBeStarted =
-                    computationalDAO.findComputationalResourcesWithStatus(user, project, exploratoryName, STOPPED);
-
-            compToBeStarted
-                    .stream()
-                    .filter(compResource -> shouldClusterBeStarted(sparkCluster, compResource))
-                    .forEach(comp -> startSpark(user, exploratoryName, comp.getComputationalName(), project));
-		}
-	}
-
-	private void terminateExploratory(SchedulerJobData job) {
-        final String user = job.getUser();
-        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), user, project, expName, String.format(AUDIT_MESSAGE, expName));
-    }
-
-	private void startSpark(String user, String expName, String compName, String project) {
-		log.debug("Starting exploratory {} computational {} for user {} by scheduler", expName, compName, user);
-		computationalService.startSparkCluster(securityService.getServiceAccountInfo(user), expName, compName, project, String.format(AUDIT_MESSAGE, expName));
-    }
-
-	private boolean shouldClusterBeStarted(DataEngineType sparkCluster, UserComputationalResource compResource) {
-		return Objects.nonNull(compResource.getSchedulerData()) && compResource.getSchedulerData().isSyncStartRequired()
-				&& compResource.getImageName().equals(getDockerImageName(sparkCluster));
-	}
-
-	/**
-	 * Performs bulk updating operation with scheduler data for corresponding to exploratory Spark clusters.
-	 * All these resources will obtain data which is equal to exploratory's except 'stopping' operation (it will be
-	 * performed automatically with notebook stopping since Spark resources have such feature).
-	 *
-	 * @param user            user's name
-	 * @param project         project name
-	 * @param exploratoryName name of exploratory resource
-	 * @param dto             scheduler job data.
-	 */
-	private void shareSchedulerJobDataToSparkClusters(String user, String project, String exploratoryName, SchedulerJobDTO dto) {
-		List<String> correspondingSparkClusters = computationalDAO.getComputationalResourcesWhereStatusIn(user, project,
-				singletonList(DataEngineType.SPARK_STANDALONE),
-				exploratoryName, STARTING, RUNNING, STOPPING, STOPPED);
-		SchedulerJobDTO dtoWithoutStopData = getSchedulerJobWithoutStopData(dto);
-		for (String sparkName : correspondingSparkClusters) {
-			log.debug("Updating computational resource {} affiliated with exploratory {} for user {} with new " +
-					"scheduler job data {}...", sparkName, exploratoryName, user, dtoWithoutStopData);
-			computationalDAO.updateSchedulerDataForComputationalResource(user, project, exploratoryName,
-					sparkName, dtoWithoutStopData);
-		}
-	}
-
-	private List<SchedulerJobData> getExploratorySchedulersForStopping(OffsetDateTime currentDateTime) {
-		return schedulerJobDAO.getExploratorySchedulerDataWithStatus(RUNNING)
-				.stream()
-				.filter(canSchedulerForStoppingBeApplied(currentDateTime, true))
-				.collect(Collectors.toList());
-	}
-
-	private List<SchedulerJobData> getExploratorySchedulersForStopping(OffsetDateTime currentDateTime,
-																	   boolean checkInactivity) {
-		final Date clusterMaxInactivityAllowedDate =
-				from(LocalDateTime.now().minusMinutes(ALLOWED_INACTIVITY_MINUTES).atZone(systemDefault()).toInstant());
-		return schedulerJobDAO.getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(RUNNING,
-				clusterMaxInactivityAllowedDate)
-				.stream()
-				.filter(canSchedulerForStoppingBeApplied(currentDateTime, false)
-						.or(schedulerJobData -> checkInactivity && exploratoryInactivityCondition(schedulerJobData)))
-				.collect(Collectors.toList());
-	}
-
-	private List<SchedulerJobData> getExploratorySchedulersForStarting(OffsetDateTime currentDateTime) {
-		return schedulerJobDAO.getExploratorySchedulerDataWithStatus(STOPPED)
-				.stream()
-				.filter(canSchedulerForStartingBeApplied(currentDateTime))
-				.collect(Collectors.toList());
-	}
-
-	private List<SchedulerJobData> getComputationalSchedulersForStarting(OffsetDateTime currentDateTime) {
-		return schedulerJobDAO
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, STOPPED)
-				.stream()
-				.filter(canSchedulerForStartingBeApplied(currentDateTime))
-				.collect(Collectors.toList());
-	}
-
-	private Predicate<SchedulerJobData> canSchedulerForStoppingBeApplied(OffsetDateTime currentDateTime, boolean usingOffset) {
-		return schedulerJobData -> shouldSchedulerBeExecuted(schedulerJobData.getJobDTO(),
-				currentDateTime, schedulerJobData.getJobDTO().getStopDaysRepeat(),
-				schedulerJobData.getJobDTO().getEndTime(), usingOffset);
-	}
-
-	private Predicate<SchedulerJobData> canSchedulerForStartingBeApplied(OffsetDateTime currentDateTime) {
-		return schedulerJobData -> shouldSchedulerBeExecuted(schedulerJobData.getJobDTO(),
-				currentDateTime, schedulerJobData.getJobDTO().getStartDaysRepeat(),
-				schedulerJobData.getJobDTO().getStartTime(), false);
-	}
-
-	private Predicate<SchedulerJobData> canSchedulerForTerminatingBeApplied(OffsetDateTime currentDateTime) {
-		return schedulerJobData -> shouldBeTerminated(currentDateTime, schedulerJobData);
-	}
-
-	private boolean shouldBeTerminated(OffsetDateTime currentDateTime, SchedulerJobData schedulerJobData) {
-		final SchedulerJobDTO jobDTO = schedulerJobData.getJobDTO();
-		final ZoneOffset timeZoneOffset = jobDTO.getTimeZoneOffset();
-		final LocalDateTime convertedCurrentTime = localDateTimeAtZone(currentDateTime, timeZoneOffset);
-		final LocalDateTime terminateDateTime = jobDTO.getTerminateDateTime();
-		return Objects.nonNull(terminateDateTime) && isSchedulerActive(jobDTO, convertedCurrentTime) &&
-				convertedCurrentTime.equals(terminateDateTime.atOffset(timeZoneOffset).toLocalDateTime());
-	}
-
-	private List<SchedulerJobData> getComputationalSchedulersForStopping(OffsetDateTime currentDateTime) {
-		return schedulerJobDAO
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING)
-				.stream()
-				.filter(canSchedulerForStoppingBeApplied(currentDateTime, true))
-				.collect(Collectors.toList());
-	}
-
-	private List<SchedulerJobData> getComputationalSchedulersForStopping(OffsetDateTime currentDateTime,
-																		 boolean checkInactivity) {
-		return schedulerJobDAO
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING)
-				.stream()
-				.filter(canSchedulerForStoppingBeApplied(currentDateTime, false)
-						.or(schedulerJobData -> checkInactivity && computationalInactivityCondition(schedulerJobData)))
-				.collect(Collectors.toList());
-	}
-
-	private boolean computationalInactivityCondition(SchedulerJobData jobData) {
-		final SchedulerJobDTO schedulerData = jobData.getJobDTO();
-		return schedulerData.isCheckInactivityRequired() && computationalInactivityExceed(jobData, schedulerData);
-	}
-
-	private boolean computationalInactivityExceed(SchedulerJobData schedulerJobData, SchedulerJobDTO schedulerData) {
-		final String projectName = schedulerJobData.getProject();
-		final String explName = schedulerJobData.getExploratoryName();
-		final String compName = schedulerJobData.getComputationalName();
-		final String user = schedulerJobData.getUser();
-		final UserComputationalResource c = computationalDAO.fetchComputationalFields(user, projectName, explName, compName);
-		final Long maxInactivity = schedulerData.getMaxInactivity();
-		return inactivityCondition(maxInactivity, c.getStatus(), c.getLastActivity());
-	}
-
-	private boolean exploratoryInactivityCondition(SchedulerJobData jobData) {
-		final SchedulerJobDTO schedulerData = jobData.getJobDTO();
-		return schedulerData.isCheckInactivityRequired() && exploratoryInactivityExceed(jobData, schedulerData);
-	}
-
-	private boolean exploratoryInactivityExceed(SchedulerJobData schedulerJobData, SchedulerJobDTO schedulerData) {
-		final String project = schedulerJobData.getProject();
-		final String expName = schedulerJobData.getExploratoryName();
-		final String user = schedulerJobData.getUser();
-		final UserInstanceDTO userInstanceDTO = exploratoryDAO.fetchExploratoryFields(user, project, expName, true);
-		final boolean canBeStopped = userInstanceDTO.getResources()
-				.stream()
-				.map(UserComputationalResource::getStatus)
-				.map(UserInstanceStatus::of)
-				.noneMatch(status -> status.in(TERMINATING, CONFIGURING, CREATING, CREATING));
-		return canBeStopped && inactivityCondition(schedulerData.getMaxInactivity(), userInstanceDTO.getStatus(),
-				userInstanceDTO.getLastActivity());
-	}
-
-	private boolean inactivityCondition(Long maxInactivity, String status, LocalDateTime lastActivity) {
-		return UserInstanceStatus.RUNNING.toString().equals(status) &&
-				Optional.ofNullable(lastActivity)
-						.map(la -> la.plusMinutes(maxInactivity).isBefore(LocalDateTime.now()))
-						.orElse(Boolean.FALSE);
-	}
-
-	private void populateDefaultSchedulerValues(SchedulerJobDTO dto) {
-		if (Objects.isNull(dto.getBeginDate()) || StringUtils.isBlank(dto.getBeginDate().toString())) {
-			dto.setBeginDate(LocalDate.now());
-		}
-		if (Objects.isNull(dto.getTimeZoneOffset()) || StringUtils.isBlank(dto.getTimeZoneOffset().toString())) {
-			dto.setTimeZoneOffset(OffsetDateTime.now(systemDefault()).getOffset());
-		}
-	}
-
-	private void validateExploratoryStatus(String user, String project, String exploratoryName) {
-		final UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(user, project, exploratoryName);
-		validateResourceStatus(userInstance.getStatus());
-	}
-
-	private void validateComputationalStatus(String user, String project, String exploratoryName, String computationalName) {
-		final UserComputationalResource computationalResource =
-				computationalDAO.fetchComputationalFields(user, project, exploratoryName, computationalName);
-		final String computationalStatus = computationalResource.getStatus();
-		validateResourceStatus(computationalStatus);
-	}
-
-	private void validateResourceStatus(String resourceStatus) {
-		final UserInstanceStatus status = UserInstanceStatus.of(resourceStatus);
-		if (Objects.isNull(status) || status.in(UserInstanceStatus.TERMINATED, TERMINATING,
-				UserInstanceStatus.FAILED)) {
-			throw new ResourceInappropriateStateException(String.format("Can not create/update scheduler for user " +
-					"instance with status: %s", status));
-		}
-	}
-
-	private boolean shouldSchedulerBeExecuted(SchedulerJobDTO dto, OffsetDateTime dateTime, List<DayOfWeek> daysRepeat,
-	                                          LocalTime time, boolean usingOffset) {
-		ZoneOffset timeZoneOffset = dto.getTimeZoneOffset();
-		LocalDateTime convertedDateTime = localDateTimeAtZone(dateTime, timeZoneOffset);
-		return isSchedulerActive(dto, convertedDateTime)
-				&& daysRepeat.contains(convertedDateTime.toLocalDate().getDayOfWeek())
-				&& timeFilter(time, convertedDateTime.toLocalTime(), timeZoneOffset, usingOffset);
-	}
-
-	private boolean timeFilter(LocalTime time, LocalTime convertedDateTime, ZoneOffset timeZoneOffset, boolean usingOffset) {
-		return usingOffset ? (time.isBefore(convertedDateTime) && time.isAfter(LocalDateTime.now(timeZoneOffset).toLocalTime())) :
-				convertedDateTime.equals(time);
-	}
-
-	private boolean isSchedulerActive(SchedulerJobDTO dto, LocalDateTime convertedDateTime) {
-		return !convertedDateTime.toLocalDate().isBefore(dto.getBeginDate())
-				&& finishDateAfterCurrentDate(dto, convertedDateTime);
-	}
-
-	private LocalDateTime localDateTimeAtZone(OffsetDateTime dateTime, ZoneOffset timeZoneOffset) {
-		return dateTime.atZoneSameInstant(ZoneOffset.UTC)
-				.truncatedTo(ChronoUnit.MINUTES)
-				.withZoneSameInstant(timeZoneOffset)
-				.toLocalDateTime();
-	}
-
-	private boolean finishDateAfterCurrentDate(SchedulerJobDTO dto, LocalDateTime currentDateTime) {
-		return Objects.isNull(dto.getFinishDate()) || !currentDateTime.toLocalDate().isAfter(dto.getFinishDate());
-	}
-
-	private SchedulerJobDTO getSchedulerJobWithoutStopData(SchedulerJobDTO dto) {
-		SchedulerJobDTO convertedDto = new SchedulerJobDTO();
-		convertedDto.setBeginDate(dto.getBeginDate());
-		convertedDto.setFinishDate(dto.getFinishDate());
-		convertedDto.setStartTime(dto.getStartTime());
-		convertedDto.setStartDaysRepeat(dto.getStartDaysRepeat());
-		convertedDto.setTerminateDateTime(dto.getTerminateDateTime());
-		convertedDto.setTimeZoneOffset(dto.getTimeZoneOffset());
-		convertedDto.setSyncStartRequired(dto.isSyncStartRequired());
-		return convertedDto;
-	}
-
-}
-
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/SystemInfoServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/SystemInfoServiceImpl.java
deleted file mode 100644
index 14ba483..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/SystemInfoServiceImpl.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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.resources.dto.SystemInfoDto;
-import com.epam.dlab.backendapi.service.SystemInfoService;
-import com.epam.dlab.model.systeminfo.DiskInfo;
-import com.epam.dlab.model.systeminfo.MemoryInfo;
-import com.epam.dlab.model.systeminfo.OsInfo;
-import com.epam.dlab.model.systeminfo.ProcessorInfo;
-import com.google.inject.Inject;
-import oshi.SystemInfo;
-import oshi.hardware.CentralProcessor;
-import oshi.hardware.GlobalMemory;
-import oshi.hardware.HardwareAbstractionLayer;
-import oshi.software.os.OperatingSystem;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-public class SystemInfoServiceImpl implements SystemInfoService {
-
-	@Inject
-	private SystemInfo si;
-
-	@Override
-	public SystemInfoDto getSystemInfo() {
-		HardwareAbstractionLayer hal = si.getHardware();
-		final OperatingSystem operatingSystem = si.getOperatingSystem();
-		return new SystemInfoDto(getOsInfo(operatingSystem), getProcessorInfo(hal), getMemoryInfo(hal),
-				getDiskInfoList(File.listRoots()));
-	}
-
-	private OsInfo getOsInfo(OperatingSystem os) {
-		return OsInfo.builder()
-				.manufacturer(os.getManufacturer())
-				.family(os.getFamily())
-				.version(os.getVersion().getVersion())
-				.buildNumber(os.getVersion().getBuildNumber())
-				.build();
-	}
-
-	private ProcessorInfo getProcessorInfo(HardwareAbstractionLayer hal) {
-		CentralProcessor cp = hal.getProcessor();
-		return ProcessorInfo.builder()
-				.model(cp.getModel())
-				.family(cp.getFamily())
-				.name(cp.getName())
-				.id(cp.getProcessorID())
-				.vendor(cp.getVendor())
-				.logicalCoreCount(cp.getLogicalProcessorCount())
-				.physicalCoreCount(cp.getPhysicalProcessorCount())
-				.isCpu64Bit(cp.isCpu64bit())
-				.currentSystemLoad(cp.getSystemCpuLoad())
-				.systemLoadAverage(cp.getSystemLoadAverage())
-				.build();
-	}
-
-	private MemoryInfo getMemoryInfo(HardwareAbstractionLayer hal) {
-		GlobalMemory memory = hal.getMemory();
-		return MemoryInfo.builder()
-				.availableMemory(memory.getAvailable())
-				.totalMemory(memory.getTotal())
-				.swapTotal(memory.getSwapTotal())
-				.swapUsed(memory.getSwapUsed())
-				.pagesPageIn(memory.getSwapPagesIn())
-				.pagesPageOut(memory.getSwapPagesOut())
-				.build();
-	}
-
-	private List<DiskInfo> getDiskInfoList(File[] roots) {
-		return Arrays.stream(roots).map(this::getDiskInfo).collect(Collectors.toList());
-	}
-
-	private DiskInfo getDiskInfo(File fileStore) {
-		return DiskInfo.builder()
-				.serialNumber(fileStore.getName())
-				.usedByteSpace(fileStore.getTotalSpace() - fileStore.getFreeSpace())
-				.totalByteSpace(fileStore.getTotalSpace())
-				.build();
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/UserGroupServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/UserGroupServiceImpl.java
deleted file mode 100644
index 0475492..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/UserGroupServiceImpl.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.annotation.Audit;
-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.ProjectDAO;
-import com.epam.dlab.backendapi.dao.UserGroupDAO;
-import com.epam.dlab.backendapi.dao.UserRoleDAO;
-import com.epam.dlab.backendapi.domain.AuditDTO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.resources.dto.UserGroupDto;
-import com.epam.dlab.backendapi.resources.dto.UserRoleDto;
-import com.epam.dlab.backendapi.roles.UserRoles;
-import com.epam.dlab.backendapi.service.AuditService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.backendapi.service.UserGroupService;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceConflictException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.CREATE;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.DELETE;
-import static com.epam.dlab.backendapi.domain.AuditActionEnum.UPDATE;
-import static com.epam.dlab.backendapi.domain.AuditResourceTypeEnum.GROUP;
-
-@Singleton
-@Slf4j
-public class UserGroupServiceImpl implements UserGroupService {
-	private static final String AUDIT_ADD_ROLE_MESSAGE = "Add role(s): %s\n";
-	private static final String AUDIT_REMOVE_ROLE_MESSAGE = "Remove role(s): %s\n";
-	private static final String AUDIT_ADD_USER_MESSAGE = "Add user(s): %s\n";
-	private static final String AUDIT_REMOVE_USER_MESSAGE = "Remove user(s): %s\n";
-	private static final String ROLE_NOT_FOUND_MSG = "Any of role : %s were not found";
-	private static final String ADMIN = "admin";
-	private static final String PROJECT_ADMIN = "projectAdmin";
-	private static final String INAPPROPRIATE_PERMISSION = "User %s doesn't have appropriate permission";
-
-	private final UserGroupDAO userGroupDao;
-	private final UserRoleDAO userRoleDao;
-	private final ProjectDAO projectDAO;
-	private final ProjectService projectService;
-	private final AuditService auditService;
-	private final SelfServiceApplicationConfiguration configuration;
-
-	@Inject
-	public UserGroupServiceImpl(UserGroupDAO userGroupDao, UserRoleDAO userRoleDao, ProjectDAO projectDAO, ProjectService projectService, AuditService auditService,
-	                            SelfServiceApplicationConfiguration configuration) {
-		this.userGroupDao = userGroupDao;
-		this.userRoleDao = userRoleDao;
-		this.projectDAO = projectDAO;
-		this.projectService = projectService;
-		this.auditService = auditService;
-		this.configuration = configuration;
-	}
-
-	@Audit(action = CREATE, type = GROUP)
-	@Override
-	public void createGroup(@User UserInfo userInfo, @ResourceName String group, Set<String> roleIds, Set<String> users) {
-		checkAnyRoleFound(roleIds, userRoleDao.addGroupToRole(Collections.singleton(group), roleIds));
-		log.debug("Adding users {} to group {}", users, group);
-		userGroupDao.addUsers(group, users);
-	}
-
-	@Override
-	public void updateGroup(UserInfo userInfo, String group, Map<String, String> roles, Set<String> users) {
-		if (UserRoles.isAdmin(userInfo)) {
-			updateGroup(userInfo.getName(), group, roles, users);
-		} else if (UserRoles.isProjectAdmin(userInfo)) {
-			projectService.getProjects(userInfo)
-					.stream()
-					.map(ProjectDTO::getGroups)
-					.flatMap(Collection::stream)
-					.filter(g -> g.equalsIgnoreCase(group))
-					.findAny()
-					.orElseThrow(() -> new DlabException(String.format(INAPPROPRIATE_PERMISSION, userInfo.getName())));
-			updateGroup(userInfo.getName(), group, roles, users);
-		} else {
-			throw new DlabException(String.format(INAPPROPRIATE_PERMISSION, userInfo.getName()));
-		}
-	}
-
-	@Audit(action = DELETE, type = GROUP)
-	@Override
-	public void removeGroup(@User UserInfo userInfo, @ResourceName String groupId) {
-		if (projectDAO.getProjectsWithEndpointStatusNotIn(UserInstanceStatus.TERMINATED,
-				UserInstanceStatus.TERMINATING)
-				.stream()
-				.map(ProjectDTO::getGroups)
-				.noneMatch(groups -> groups.contains(groupId))) {
-			userRoleDao.removeGroup(groupId);
-			userGroupDao.removeGroup(groupId);
-		} else {
-			throw new ResourceConflictException("Group can not be removed because it is used in some project");
-		}
-	}
-
-	@Override
-	public List<UserGroupDto> getAggregatedRolesByGroup(UserInfo user) {
-		if (UserRoles.isAdmin(user)) {
-			return userRoleDao.aggregateRolesByGroup();
-		} else if (UserRoles.isProjectAdmin(user)) {
-			Set<String> groups = projectService.getProjects(user)
-					.stream()
-					.map(ProjectDTO::getGroups)
-					.flatMap(Collection::stream)
-					.collect(Collectors.toSet());
-			return userRoleDao.aggregateRolesByGroup()
-					.stream()
-					.filter(userGroup -> groups.contains(userGroup.getGroup()) && !containsAdministrationPermissions(userGroup))
-					.collect(Collectors.toList());
-		} else {
-			throw new DlabException(String.format(INAPPROPRIATE_PERMISSION, user.getName()));
-		}
-	}
-
-	private boolean containsAdministrationPermissions(UserGroupDto userGroup) {
-		List<String> ids = userGroup.getRoles()
-				.stream()
-				.map(UserRoleDto::getId)
-				.collect(Collectors.toList());
-		return ids.contains(ADMIN) || ids.contains(PROJECT_ADMIN);
-	}
-
-	private void updateGroup(String user, String group, Map<String, String> roles, Set<String> users) {
-		Set<String> roleIds = roles.keySet();
-		if (configuration.isAuditEnabled()) {
-			audit(user, group, roles, users);
-		}
-		log.debug("Updating users for group {}: {}", group, users);
-		userGroupDao.updateUsers(group, users);
-		log.debug("Removing group {} from existing roles", group);
-		userRoleDao.removeGroupWhenRoleNotIn(group, roleIds);
-		log.debug("Adding group {} to roles {}", group, roleIds);
-		userRoleDao.addGroupToRole(Collections.singleton(group), roleIds);
-	}
-
-	private void audit(String user, String group, Map<String, String> newRoles, Set<String> users) {
-		final String auditInfo = roleAudit(group, newRoles) + getUserAudit(group, users);
-		AuditDTO auditDTO = AuditDTO.builder()
-				.user(user)
-				.resourceName(group)
-				.action(UPDATE)
-				.type(GROUP)
-				.info(auditInfo)
-				.build();
-		auditService.save(auditDTO);
-	}
-
-	private String getUserAudit(String group, Set<String> users) {
-		StringBuilder auditInfo = new StringBuilder();
-		Set<String> oldUsers = userGroupDao.getUsers(group);
-		HashSet<String> newUsers = new HashSet<>(users);
-		newUsers.removeAll(oldUsers);
-		if (!newUsers.isEmpty()) {
-			auditInfo.append(String.format(AUDIT_ADD_USER_MESSAGE, String.join(", ", newUsers)));
-		}
-		HashSet<String> removedUsers = new HashSet<>(oldUsers);
-		removedUsers.removeAll(users);
-		if (!removedUsers.isEmpty()) {
-			auditInfo.append(String.format(AUDIT_REMOVE_USER_MESSAGE, String.join(", ", removedUsers)));
-		}
-		return auditInfo.toString();
-	}
-
-	private String roleAudit(String group, Map<String, String> newRoles) {
-		StringBuilder auditInfo = new StringBuilder();
-		Map<String, String> oldRoles = userRoleDao.aggregateRolesByGroup()
-				.stream()
-				.filter(g -> g.getGroup().equals(group))
-				.map(UserGroupDto::getRoles)
-				.flatMap(Collection::stream)
-				.collect(Collectors.toMap(UserRoleDto::getId, UserRoleDto::getDescription));
-		if (!getRoleDescription(oldRoles, newRoles).isEmpty()) {
-			auditInfo.append(String.format(AUDIT_ADD_ROLE_MESSAGE, getRoleDescription(oldRoles, newRoles)));
-		}
-		if (!getRoleDescription(newRoles, oldRoles).isEmpty()) {
-			auditInfo.append(String.format(AUDIT_REMOVE_ROLE_MESSAGE, getRoleDescription(newRoles, oldRoles)));
-		}
-		return auditInfo.toString();
-	}
-
-	private String getRoleDescription(Map<String, String> newRoles, Map<String, String> oldRoles) {
-		Set<String> removedRoleIds = new HashSet<>(oldRoles.keySet());
-		removedRoleIds.removeAll(newRoles.keySet());
-		return removedRoleIds
-				.stream()
-				.map(oldRoles::get)
-				.collect(Collectors.joining(", "));
-	}
-
-	private void checkAnyRoleFound(Set<String> roleIds, boolean anyRoleFound) {
-		if (!anyRoleFound) {
-			throw new ResourceNotFoundException(String.format(ROLE_NOT_FOUND_MSG, roleIds));
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/servlet/guacamole/GuacamoleServlet.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/servlet/guacamole/GuacamoleServlet.java
deleted file mode 100644
index aa7995f..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/servlet/guacamole/GuacamoleServlet.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.servlet.guacamole;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.SecurityDAO;
-import com.epam.dlab.backendapi.service.GuacamoleService;
-import com.epam.dlab.exceptions.DlabAuthenticationException;
-import com.epam.dlab.exceptions.DlabException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.inject.Inject;
-import lombok.Data;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.guacamole.net.GuacamoleTunnel;
-import org.apache.guacamole.servlet.GuacamoleHTTPTunnelServlet;
-import org.apache.http.HttpStatus;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.core.HttpHeaders;
-import java.io.IOException;
-
-@Slf4j
-public class GuacamoleServlet extends GuacamoleHTTPTunnelServlet {
-	private static final String UNAUTHORIZED_MSG = "User is not authenticated";
-	private static final String DLAB_PREFIX = "DLab-";
-	private final GuacamoleService guacamoleService;
-	private final ObjectMapper mapper;
-	private final SecurityDAO securityDAO;
-	private static final String AUTH_HEADER_PREFIX = "Bearer ";
-
-	@Inject
-	public GuacamoleServlet(GuacamoleService guacamoleService, ObjectMapper mapper, SecurityDAO securityDAO) {
-		this.mapper = mapper;
-		this.guacamoleService = guacamoleService;
-		this.securityDAO = securityDAO;
-	}
-
-	@Override
-	protected GuacamoleTunnel doConnect(HttpServletRequest request) {
-		try {
-			final String authorization = request.getHeader(DLAB_PREFIX + HttpHeaders.AUTHORIZATION);
-			final String credentials = StringUtils.substringAfter(authorization, AUTH_HEADER_PREFIX);
-			final UserInfo userInfo = getUserInfo(credentials);
-			final CreateTerminalDTO createTerminalDTO = mapper.readValue(request.getReader(), CreateTerminalDTO.class);
-			return guacamoleService.getTunnel(userInfo, createTerminalDTO.getHost(), createTerminalDTO.getEndpoint());
-		} catch (IOException e) {
-			log.error("Cannot read request body. Reason {}", e.getMessage(), e);
-			throw new DlabException("Can not read request body: " + e.getMessage(), e);
-		}
-	}
-
-	@Override
-	protected void handleTunnelRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException {
-		try {
-			super.handleTunnelRequest(request, response);
-		} catch (DlabAuthenticationException e) {
-			log.error(UNAUTHORIZED_MSG, e);
-			sendError(response, HttpStatus.SC_UNAUTHORIZED, HttpStatus.SC_UNAUTHORIZED, UNAUTHORIZED_MSG);
-		}
-	}
-
-	private UserInfo getUserInfo(String credentials) {
-		try {
-			return securityDAO.getUser(credentials)
-					.orElseThrow(() -> new DlabAuthenticationException(UNAUTHORIZED_MSG));
-		} catch (DlabAuthenticationException e) {
-			log.error(UNAUTHORIZED_MSG, e);
-			throw new DlabException(UNAUTHORIZED_MSG);
-		}
-	}
-
-	@Data
-	private static class CreateTerminalDTO {
-		private String host;
-		private String endpoint;
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/BillingUtils.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/util/BillingUtils.java
deleted file mode 100644
index 91e4809..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/BillingUtils.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * 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.util;
-
-import com.epam.dlab.backendapi.domain.BillingReportLine;
-import com.epam.dlab.backendapi.resources.dto.ImageInfoRecord;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import jersey.repackaged.com.google.common.collect.Lists;
-import org.apache.commons.lang3.StringUtils;
-
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Stream;
-
-import static com.epam.dlab.dto.billing.BillingResourceType.BUCKET;
-import static com.epam.dlab.dto.billing.BillingResourceType.COMPUTATIONAL;
-import static com.epam.dlab.dto.billing.BillingResourceType.EDGE;
-import static com.epam.dlab.dto.billing.BillingResourceType.ENDPOINT;
-import static com.epam.dlab.dto.billing.BillingResourceType.EXPLORATORY;
-import static com.epam.dlab.dto.billing.BillingResourceType.IMAGE;
-import static com.epam.dlab.dto.billing.BillingResourceType.SSN;
-import static com.epam.dlab.dto.billing.BillingResourceType.VOLUME;
-
-public class BillingUtils {
-    private static final String[] AVAILABLE_NOTEBOOKS = {"zeppelin", "tensor-rstudio", "rstudio", "tensor", "superset", "jupyterlab", "jupyter", "deeplearning"};
-    private static final String[] BILLING_FILTERED_REPORT_HEADERS = {"DLab ID", "Project", "DLab Resource Type", "Status", "Shape", "Product", "Cost"};
-    private static final String[] COMPLETE_REPORT_REPORT_HEADERS = {"DLab ID", "User", "Project", "DLab Resource Type", "Status", "Shape", "Product", "Cost"};
-    private static final String REPORT_FIRST_LINE = "Service base name: %s. Available reporting period from: %s to: %s";
-    private static final String TOTAL_LINE = "Total: %s %s";
-    private static final String SSN_FORMAT = "%s-ssn";
-    private static final String ENDPOINT_FORMAT = "%s-%s-endpoint";
-    private static final String EDGE_FORMAT = "%s-%s-%s-edge";
-    private static final String EDGE_VOLUME_FORMAT = "%s-%s-%s-edge-volume-primary";
-    private static final String PROJECT_ENDPOINT_BUCKET_FORMAT = "%s-%s-%s-bucket";
-    private static final String ENDPOINT_SHARED_BUCKET_FORMAT = "%s-%s-shared-bucket";
-    private static final String VOLUME_PRIMARY_FORMAT = "%s-volume-primary";
-    private static final String VOLUME_PRIMARY_COMPUTATIONAL_FORMAT = "%s-%s-volume-primary";
-    private static final String VOLUME_SECONDARY_FORMAT = "%s-volume-secondary";
-    private static final String VOLUME_SECONDARY_COMPUTATIONAL_FORMAT = "%s-%s-volume-secondary";
-    private static final String IMAGE_STANDARD_FORMAT1 = "%s-%s-%s-%s-notebook-image";
-    private static final String IMAGE_STANDARD_FORMAT2 = "%s-%s-%s-notebook-image";
-    private static final String IMAGE_CUSTOM_FORMAT = "%s-%s-%s-%s-%s";
-
-    private static final String SHARED_RESOURCE = "Shared resource";
-    private static final String IMAGE_NAME = "Image";
-
-    private static final String DATAENGINE_NAME_FORMAT = "%d x %s";
-    private static final String DATAENGINE_SERVICE_NAME_FORMAT = "Master: %sSlave: %d x %s";
-
-    public static Stream<BillingReportLine> edgeBillingDataStream(String project, String sbn, String endpoint) {
-        final String userEdgeId = String.format(EDGE_FORMAT, sbn, project, endpoint).toLowerCase();
-        final String edgeVolumeId = String.format(EDGE_VOLUME_FORMAT, sbn, project, endpoint).toLowerCase();
-        final String endpointBucketId = String.format(PROJECT_ENDPOINT_BUCKET_FORMAT, sbn, project, endpoint).toLowerCase();
-
-        return Stream.concat(Stream.of(
-                BillingReportLine.builder().resourceName(endpoint).user(SHARED_RESOURCE).project(project).dlabId(userEdgeId).resourceType(EDGE).build(),
-                BillingReportLine.builder().resourceName("EDGE volume").user(SHARED_RESOURCE).project(project).dlabId(edgeVolumeId).resourceType(VOLUME).build(),
-                BillingReportLine.builder().resourceName("Project endpoint shared bucket").user(SHARED_RESOURCE).project(project).dlabId(endpointBucketId).resourceType(BUCKET).build()
-                ),
-                standardImageBillingDataStream(sbn, project, endpoint)
-        );
-    }
-
-    public static Stream<BillingReportLine> ssnBillingDataStream(String sbn) {
-        final String ssnId = String.format(SSN_FORMAT, sbn);
-        return Stream.of(
-                BillingReportLine.builder().user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceName("SSN").dlabId(ssnId).resourceType(SSN).build(),
-                BillingReportLine.builder().user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceName("SSN Volume").dlabId(String.format(VOLUME_PRIMARY_FORMAT, ssnId)).resourceType(VOLUME).build()
-        );
-    }
-
-    public static Stream<BillingReportLine> sharedEndpointBillingDataStream(String endpoint, String sbn) {
-        final String projectEndpointBucketId = String.format(ENDPOINT_SHARED_BUCKET_FORMAT, sbn, endpoint).toLowerCase();
-        final String endpointId = String.format(ENDPOINT_FORMAT, sbn, endpoint).toLowerCase();
-        return Stream.concat(Stream.of(
-                BillingReportLine.builder().resourceName("Endpoint shared bucket").user(SHARED_RESOURCE).project(SHARED_RESOURCE).dlabId(projectEndpointBucketId).resourceType(BUCKET).build(),
-                BillingReportLine.builder().resourceName("Endpoint").user(SHARED_RESOURCE).project(SHARED_RESOURCE).dlabId(endpointId).resourceType(ENDPOINT).build()
-                ),
-                standardImageBillingDataStream(sbn, endpoint));
-    }
-
-    public static Stream<BillingReportLine> exploratoryBillingDataStream(UserInstanceDTO userInstance, Integer maxSparkInstanceCount) {
-        final Stream<BillingReportLine> computationalStream = userInstance.getResources()
-                .stream()
-                .filter(cr -> cr.getComputationalId() != null)
-                .flatMap(cr -> {
-                    final String computationalId = cr.getComputationalId().toLowerCase();
-                    return Stream.concat(Stream.of(
-                            withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).dlabId(computationalId).resourceType(COMPUTATIONAL).shape(getComputationalShape(cr))
-                                    .exploratoryName(userInstance.getExploratoryName()).build(),
-                            withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).dlabId(String.format(VOLUME_PRIMARY_FORMAT, computationalId)).resourceType(VOLUME).build(),
-                            withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).dlabId(String.format(VOLUME_SECONDARY_FORMAT, computationalId)).resourceType(VOLUME).build(),
-                            withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).dlabId(String.format(VOLUME_PRIMARY_COMPUTATIONAL_FORMAT, computationalId, "m"))
-                                    .resourceType(VOLUME).build(),
-                            withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).dlabId(String.format(VOLUME_SECONDARY_COMPUTATIONAL_FORMAT, computationalId, "m"))
-                                    .resourceType(VOLUME).build()
-                            ),
-                            getSlaveVolumes(userInstance, cr, maxSparkInstanceCount)
-                    );
-                });
-        final String exploratoryName = userInstance.getExploratoryName();
-        final String exploratoryId = userInstance.getExploratoryId().toLowerCase();
-        final String primaryVolumeId = String.format(VOLUME_PRIMARY_FORMAT, exploratoryId);
-        final String secondaryVolumeId = String.format(VOLUME_SECONDARY_FORMAT, exploratoryId);
-        final Stream<BillingReportLine> exploratoryStream = Stream.of(
-                withUserProjectEndpoint(userInstance).resourceName(exploratoryName).dlabId(exploratoryId).resourceType(EXPLORATORY).shape(userInstance.getShape()).build(),
-                withUserProjectEndpoint(userInstance).resourceName(exploratoryName).dlabId(primaryVolumeId).resourceType(VOLUME).build(),
-                withUserProjectEndpoint(userInstance).resourceName(exploratoryName).dlabId(secondaryVolumeId).resourceType(VOLUME).build());
-
-        return Stream.concat(computationalStream, exploratoryStream);
-    }
-
-    public static Stream<BillingReportLine> customImageBillingDataStream(ImageInfoRecord image, String sbn) {
-        String imageId = String.format(IMAGE_CUSTOM_FORMAT, sbn, image.getProject(), image.getEndpoint(), image.getApplication(), image.getName()).toLowerCase();
-        return Stream.of(
-                BillingReportLine.builder().resourceName(image.getName()).project(image.getProject()).dlabId(imageId).user(image.getUser()).resourceType(IMAGE).build()
-        );
-    }
-
-    private static Stream<BillingReportLine> getSlaveVolumes(UserInstanceDTO userInstance, UserComputationalResource cr, Integer maxSparkInstanceCount) {
-        List<BillingReportLine> list = new ArrayList<>();
-        for (int i = 1; i <= maxSparkInstanceCount; i++) {
-            list.add(withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).dlabId(String.format(VOLUME_PRIMARY_COMPUTATIONAL_FORMAT, cr.getComputationalId().toLowerCase(), "s" + i))
-                    .resourceType(VOLUME).build());
-            list.add(withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).dlabId(String.format(VOLUME_SECONDARY_COMPUTATIONAL_FORMAT, cr.getComputationalId().toLowerCase(), "s" + i))
-                    .resourceType(VOLUME).build());
-        }
-        return list.stream();
-    }
-
-    private static BillingReportLine.BillingReportLineBuilder withUserProjectEndpoint(UserInstanceDTO userInstance) {
-        return BillingReportLine.builder().user(userInstance.getUser()).project(userInstance.getProject()).endpoint(userInstance.getEndpoint());
-    }
-
-    public static String getComputationalShape(UserComputationalResource resource) {
-        return DataEngineType.fromDockerImageName(resource.getImageName()) == DataEngineType.SPARK_STANDALONE ?
-                String.format(DATAENGINE_NAME_FORMAT, resource.getDataengineInstanceCount(), resource.getDataengineShape()) :
-                String.format(DATAENGINE_SERVICE_NAME_FORMAT, resource.getMasterNodeShape(), resource.getTotalInstanceCount() - 1, resource.getSlaveNodeShape());
-    }
-
-    private static Stream<BillingReportLine> standardImageBillingDataStream(String sbn, String endpoint) {
-        List<BillingReportLine> list = new ArrayList<>();
-        for (String notebook : AVAILABLE_NOTEBOOKS) {
-            list.add(BillingReportLine.builder().resourceName(IMAGE_NAME).dlabId(String.format(IMAGE_STANDARD_FORMAT2, sbn, endpoint, notebook).toLowerCase())
-                    .user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceType(IMAGE).build());
-        }
-
-        return list.stream();
-    }
-
-    private static Stream<BillingReportLine> standardImageBillingDataStream(String sbn, String project, String endpoint) {
-        List<BillingReportLine> list = new ArrayList<>();
-        for (String notebook : AVAILABLE_NOTEBOOKS) {
-            list.add(BillingReportLine.builder().resourceName(IMAGE_NAME).dlabId(String.format(IMAGE_STANDARD_FORMAT1, sbn, project, endpoint, notebook).toLowerCase())
-                    .project(project).user(SHARED_RESOURCE).resourceType(IMAGE).build());
-        }
-
-        return list.stream();
-    }
-
-    /**
-     *
-     * @param sbn Service Base Name
-     * @param from formatted date, like 2020-04-07
-     * @param to formatted date, like 2020-05-07
-     * @return line, like:
-     * "Service base name: SERVICE_BASE_NAME. Available reporting period from: 2020-04-07 to: 2020-04-07"
-     */
-    public static String getFirstLine(String sbn, LocalDate from, LocalDate to) {
-        return CSVFormatter.formatLine(Lists.newArrayList(String.format(REPORT_FIRST_LINE, sbn,
-                Optional.ofNullable(from).map(date -> date.format(DateTimeFormatter.ISO_DATE)).orElse(StringUtils.EMPTY),
-                Optional.ofNullable(to).map(date -> date.format(DateTimeFormatter.ISO_DATE)).orElse(StringUtils.EMPTY))),
-                CSVFormatter.SEPARATOR, '\"');
-    }
-
-    /**
-     * headerType there are two types of header according user role
-     * @return line, like DLab ID,User,Project,DLab Resource Type,Status,Shape,Product,Cost
-     * in case of additional header type, the ENUM object will be propagated from the Service Impl Class
-     */
-    public static String getHeader(boolean isReportHeaderCompletable) {
-        if (!isReportHeaderCompletable){
-            return CSVFormatter.formatLine(Arrays.asList(BillingUtils.BILLING_FILTERED_REPORT_HEADERS), CSVFormatter.SEPARATOR);
-        }
-        return CSVFormatter.formatLine(Arrays.asList(BillingUtils.COMPLETE_REPORT_REPORT_HEADERS), CSVFormatter.SEPARATOR);
-    }
-
-    public static String printLine(BillingReportLine line, boolean isReportHeaderCompletable) {
-        List<String> lines = new ArrayList<>();
-        lines.add(getOrEmpty(line.getDlabId()));
-        //if user does not have the billing role, the User field should not be present in report
-        if (isReportHeaderCompletable) {
-            lines.add(getOrEmpty(line.getUser()));
-        }
-        lines.add(getOrEmpty(line.getProject()));
-        lines.add(getOrEmpty(Optional.ofNullable(line.getResourceType()).map(r -> StringUtils.capitalize(r.toString().toLowerCase())).orElse(null)));
-        lines.add(getOrEmpty(Optional.ofNullable(line.getStatus()).map(UserInstanceStatus::toString).orElse(null)));
-        lines.add(getOrEmpty(line.getShape()));
-        lines.add(getOrEmpty(line.getProduct()));
-        lines.add(getOrEmpty(Optional.ofNullable(line.getCost()).map(String::valueOf).orElse(null)));
-        return CSVFormatter.formatLine(lines, CSVFormatter.SEPARATOR);
-    }
-
-    /**
-     *
-     * @param total monetary amount
-     * @param currency user's currency
-     * @param stringOfAdjustedHeader filtered fields of report header
-     * @return line with cost of resources
-     */
-    public static String getTotal(Double total, String currency, String stringOfAdjustedHeader) {
-        List<String> totalLine = new ArrayList<>();
-        String[] headerFieldsList = stringOfAdjustedHeader.split(String.valueOf(CSVFormatter.SEPARATOR));
-        for (int i = 0; i < headerFieldsList.length - 1; i++) {
-            totalLine.add(StringUtils.EMPTY);
-        }
-        totalLine.add(headerFieldsList.length - 1, String.format(TOTAL_LINE, getOrEmpty(String.valueOf(total)), getOrEmpty(currency)));
-        return CSVFormatter.formatLine(totalLine, CSVFormatter.SEPARATOR);
-
-    }
-
-    private static String getOrEmpty(String s) {
-        return Objects.nonNull(s) ? s : StringUtils.EMPTY;
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/CSVFormatter.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/util/CSVFormatter.java
deleted file mode 100644
index a42a76d..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/CSVFormatter.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.util;
-
-import java.util.List;
-
-public class CSVFormatter {
-	public static final char SEPARATOR = ',';
-
-	private CSVFormatter() {
-	}
-
-
-	public static String formatLine(List<String> values, char separator) {
-		boolean first = true;
-		StringBuilder builder = new StringBuilder();
-		for (String value : values) {
-			if (!first) {
-				builder.append(separator);
-			}
-			builder.append(followCsvStandard(value));
-			first = false;
-        }
-        return builder.append(System.lineSeparator()).toString();
-    }
-
-    public static String formatLine(List<String> values, char separator, char customQuote) {
-        boolean first = true;
-        StringBuilder builder = new StringBuilder();
-        for (String value : values) {
-            if (!first) {
-                builder.append(separator);
-            }
-            builder.append(customQuote).append(followCsvStandard(value)).append(customQuote);
-            first = false;
-        }
-        return builder.append(System.lineSeparator()).toString();
-    }
-
-    private static String followCsvStandard(String value) {
-
-        String result = value;
-        if (result.contains("\"")) {
-            result = result.replace("\"", "\"\"");
-        }
-        return result;
-
-    }
-
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/DateRemoverUtil.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/util/DateRemoverUtil.java
deleted file mode 100644
index 12bf3e6..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/DateRemoverUtil.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.util;
-
-/**
- * Created on 3/15/2017.
- */
-public class DateRemoverUtil {
-
-	private static final String ERROR_DATE_FORMAT = "\\[Error-\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\]:";
-	private static final String ERROR_WITHOUT_DATE_FORMAT = "\\[Error\\]:";
-
-	private DateRemoverUtil() {
-	}
-
-    public static String removeDateFormErrorMessage(String errorMessage, String errorDateFormat, String replaceWith) {
-        return errorMessage.replaceAll(errorDateFormat, replaceWith);
-    }
-
-    public static String removeDateFormErrorMessage(String errorMessage) {
-        return errorMessage.replaceAll(ERROR_DATE_FORMAT, ERROR_WITHOUT_DATE_FORMAT);
-    }
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/KeycloakUtil.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/util/KeycloakUtil.java
deleted file mode 100644
index 94e1957..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/KeycloakUtil.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.util;
-
-import com.epam.dlab.exceptions.DlabException;
-import org.keycloak.common.util.Base64Url;
-import org.keycloak.representations.IDToken;
-import org.keycloak.util.JsonSerialization;
-
-public class KeycloakUtil {
-
-	public static IDToken parseToken(String encoded) {
-		try {
-			String[] parts = encoded.split("\\.");
-			if (parts.length < 2 || parts.length > 3) {
-				throw new IllegalArgumentException("Parsing error");
-			}
-			byte[] bytes = Base64Url.decode(parts[1]);
-			return JsonSerialization.readValue(bytes, IDToken.class);
-		} catch (Exception e) {
-			throw new DlabException("Can not parse token due to: " + e.getMessage(), e);
-		}
-	}
-}
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
deleted file mode 100644
index ebc5fb9..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/RequestBuilder.java
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
- * 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.util;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.SettingsDAO;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.resources.dto.BackupFormDTO;
-import com.epam.dlab.backendapi.resources.dto.ComputationalCreateFormDTO;
-import com.epam.dlab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
-import com.epam.dlab.backendapi.resources.dto.aws.AwsComputationalCreateForm;
-import com.epam.dlab.backendapi.resources.dto.gcp.GcpComputationalCreateForm;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.LibListComputationalDTO;
-import com.epam.dlab.dto.LibListExploratoryDTO;
-import com.epam.dlab.dto.ResourceBaseDTO;
-import com.epam.dlab.dto.ResourceSysBaseDTO;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.aws.AwsCloudSettings;
-import com.epam.dlab.dto.aws.computational.AwsComputationalTerminateDTO;
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.dto.aws.computational.ComputationalCreateAws;
-import com.epam.dlab.dto.aws.computational.SparkComputationalCreateAws;
-import com.epam.dlab.dto.aws.exploratory.ExploratoryCreateAws;
-import com.epam.dlab.dto.azure.AzureCloudSettings;
-import com.epam.dlab.dto.azure.computational.SparkComputationalCreateAzure;
-import com.epam.dlab.dto.azure.exploratory.ExploratoryActionStartAzure;
-import com.epam.dlab.dto.azure.exploratory.ExploratoryActionStopAzure;
-import com.epam.dlab.dto.azure.exploratory.ExploratoryCreateAzure;
-import com.epam.dlab.dto.backup.EnvBackupDTO;
-import com.epam.dlab.dto.base.CloudSettings;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.base.computational.ComputationalBase;
-import com.epam.dlab.dto.computational.ComputationalCheckInactivityDTO;
-import com.epam.dlab.dto.computational.ComputationalClusterConfigDTO;
-import com.epam.dlab.dto.computational.ComputationalStartDTO;
-import com.epam.dlab.dto.computational.ComputationalStopDTO;
-import com.epam.dlab.dto.computational.ComputationalTerminateDTO;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.dto.exploratory.ExploratoryActionDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryCheckInactivityAction;
-import com.epam.dlab.dto.exploratory.ExploratoryCreateDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryImageDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
-import com.epam.dlab.dto.exploratory.LibInstallDTO;
-import com.epam.dlab.dto.exploratory.LibraryInstallDTO;
-import com.epam.dlab.dto.gcp.GcpCloudSettings;
-import com.epam.dlab.dto.gcp.computational.ComputationalCreateGcp;
-import com.epam.dlab.dto.gcp.computational.GcpComputationalTerminateDTO;
-import com.epam.dlab.dto.gcp.computational.SparkComputationalCreateGcp;
-import com.epam.dlab.dto.gcp.exploratory.ExploratoryCreateGcp;
-import com.epam.dlab.dto.project.ProjectActionDTO;
-import com.epam.dlab.dto.project.ProjectCreateDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.model.exploratory.Exploratory;
-import com.epam.dlab.util.UsernameUtils;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-import static com.epam.dlab.cloud.CloudProvider.AWS;
-import static com.epam.dlab.cloud.CloudProvider.AZURE;
-import static com.epam.dlab.cloud.CloudProvider.GCP;
-
-@Singleton
-public class RequestBuilder {
-	private static final String UNSUPPORTED_CLOUD_PROVIDER_MESSAGE = "Unsupported cloud provider ";
-	private static final String AZURE_REFRESH_TOKEN_KEY = "refresh_token";
-
-	@Inject
-	private SelfServiceApplicationConfiguration configuration;
-	@Inject
-	private SettingsDAO settingsDAO;
-
-	private CloudSettings cloudSettings(String user, CloudProvider cloudProvider) {
-		switch (cloudProvider) {
-			case AWS:
-				return AwsCloudSettings.builder()
-						.awsIamUser(user)
-						.build();
-			case AZURE:
-				return AzureCloudSettings.builder()
-						.azureIamUser(user).build();
-			case GCP:
-				return GcpCloudSettings.builder()
-						.gcpIamUser(user).build();
-			default:
-				throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
-		}
-	}
-
-	@SuppressWarnings("unchecked")
-	private <T extends ResourceBaseDTO<?>> T newResourceBaseDTO(String user, CloudProvider cloudProvider,
-																Class<T> resourceClass) {
-		try {
-			return (T) resourceClass.newInstance()
-					.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(String user, CloudProvider cloudProvider) {
-		String edgeUser = UsernameUtils.removeDomain(user);
-		switch (cloudProvider) {
-			case GCP:
-				return adjustUserName(configuration.getMaxUserNameLength(), edgeUser);
-			case AWS:
-			case AZURE:
-				return edgeUser;
-			default:
-				throw new DlabException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
-		}
-	}
-
-	private String adjustUserName(int maxLength, String userName) {
-		return userName.length() > maxLength ?
-				UUID.nameUUIDFromBytes(userName.getBytes()).toString().substring(0, maxLength) : userName;
-	}
-
-	@SuppressWarnings("unchecked")
-	private <T extends ResourceSysBaseDTO<?>> T newResourceSysBaseDTO(String user, CloudProvider cloudProvider,
-																	  Class<T> resourceClass) {
-		return newResourceBaseDTO(user, cloudProvider, resourceClass);
-	}
-
-	@SuppressWarnings("unchecked")
-	public <T extends ExploratoryCreateDTO<T>> T newExploratoryCreate(ProjectDTO projectDTO, EndpointDTO endpointDTO, Exploratory exploratory,
-																	  UserInfo userInfo,
-																	  ExploratoryGitCredsDTO exploratoryGitCredsDTO,
-																	  Map<String, String> tags) {
-
-		T exploratoryCreate;
-		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
-		switch (cloudProvider) {
-			case AWS:
-				exploratoryCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryCreateAws.class)
-						.withNotebookInstanceType(exploratory.getShape());
-				break;
-			case AZURE:
-				exploratoryCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryCreateAzure.class)
-						.withNotebookInstanceSize(exploratory.getShape());
-				if (settingsDAO.isAzureDataLakeEnabled()) {
-					((ExploratoryCreateAzure) exploratoryCreate)
-							.withAzureUserRefreshToken(userInfo.getKeys().get(AZURE_REFRESH_TOKEN_KEY));
-				}
-
-				((ExploratoryCreateAzure) exploratoryCreate)
-						.withAzureDataLakeEnabled(Boolean.toString(settingsDAO.isAzureDataLakeEnabled()));
-				break;
-			case GCP:
-				exploratoryCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryCreateGcp.class)
-						.withNotebookInstanceType(exploratory.getShape());
-				break;
-			default:
-				throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
-		}
-
-		return exploratoryCreate.withExploratoryName(exploratory.getName())
-				.withNotebookImage(exploratory.getDockerImage())
-				.withApplicationName(getApplicationNameFromImage(exploratory.getDockerImage()))
-				.withGitCreds(exploratoryGitCredsDTO.getGitCreds())
-				.withImageName(exploratory.getImageName())
-				.withClusterConfig(exploratory.getClusterConfig())
-				.withProject(exploratory.getProject())
-				.withEndpoint(exploratory.getEndpoint())
-				.withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()))
-				.withTags(tags);
-	}
-
-	@SuppressWarnings("unchecked")
-	public <T extends ExploratoryGitCredsUpdateDTO> T newExploratoryStart(UserInfo userInfo,
-																		  UserInstanceDTO userInstance,
-																		  EndpointDTO endpointDTO,
-																		  ExploratoryGitCredsDTO
-																				  exploratoryGitCredsDTO) {
-		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
-		switch (cloudProvider) {
-			case AWS:
-			case GCP:
-				return (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryGitCredsUpdateDTO.class)
-						.withNotebookInstanceName(userInstance.getExploratoryId())
-						.withGitCreds(exploratoryGitCredsDTO.getGitCreds())
-						.withNotebookImage(userInstance.getImageName())
-						.withExploratoryName(userInstance.getExploratoryName())
-						.withReuploadKeyRequired(userInstance.isReuploadKeyRequired())
-						.withProject(userInstance.getProject())
-						.withEndpoint(userInstance.getEndpoint());
-			case AZURE:
-				T exploratoryStart = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryActionStartAzure.class)
-						.withNotebookInstanceName(userInstance.getExploratoryId())
-						.withGitCreds(exploratoryGitCredsDTO.getGitCreds())
-						.withNotebookImage(userInstance.getImageName())
-						.withExploratoryName(userInstance.getExploratoryName())
-						.withReuploadKeyRequired(userInstance.isReuploadKeyRequired())
-						.withProject(userInstance.getProject())
-						.withEndpoint(userInstance.getEndpoint());
-
-				if (settingsDAO.isAzureDataLakeEnabled()) {
-					((ExploratoryActionStartAzure) exploratoryStart)
-							.withAzureUserRefreshToken(userInfo.getKeys().get(AZURE_REFRESH_TOKEN_KEY));
-				}
-
-				((ExploratoryActionStartAzure) exploratoryStart)
-						.withAzureDataLakeEnabled(Boolean.toString(settingsDAO.isAzureDataLakeEnabled()));
-
-				return exploratoryStart;
-			default:
-				throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
-		}
-	}
-
-	@SuppressWarnings("unchecked")
-	public <T extends ExploratoryActionDTO<T>> T newExploratoryStop(String user, UserInstanceDTO userInstance, EndpointDTO endpointDTO) {
-
-		T exploratoryStop;
-		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
-
-		switch (cloudProvider) {
-			case AWS:
-			case GCP:
-				exploratoryStop = (T) newResourceSysBaseDTO(user, cloudProvider, ExploratoryActionDTO.class);
-				break;
-			case AZURE:
-				exploratoryStop = (T) newResourceSysBaseDTO(user, cloudProvider, ExploratoryActionStopAzure.class);
-				break;
-			default:
-				throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
-		}
-
-		return exploratoryStop
-				.withNotebookInstanceName(userInstance.getExploratoryId())
-				.withNotebookImage(userInstance.getImageName())
-				.withExploratoryName(userInstance.getExploratoryName())
-				.withNotebookImage(userInstance.getImageName())
-				.withReuploadKeyRequired(userInstance.isReuploadKeyRequired())
-				.withProject(userInstance.getProject())
-				.withEndpoint(userInstance.getEndpoint());
-	}
-
-	public ExploratoryGitCredsUpdateDTO newGitCredentialsUpdate(UserInfo userInfo, UserInstanceDTO instanceDTO,
-																EndpointDTO endpointDTO,
-																ExploratoryGitCredsDTO exploratoryGitCredsDTO) {
-		checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
-		return newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ExploratoryGitCredsUpdateDTO.class)
-				.withNotebookImage(instanceDTO.getImageName())
-				.withApplicationName(getApplicationNameFromImage(instanceDTO.getImageName()))
-				.withProject(instanceDTO.getProject())
-				.withEndpoint(instanceDTO.getEndpoint())
-				.withNotebookInstanceName(instanceDTO.getExploratoryId())
-				.withExploratoryName(instanceDTO.getExploratoryName())
-				.withGitCreds(exploratoryGitCredsDTO.getGitCreds());
-	}
-
-	public LibraryInstallDTO newLibInstall(UserInfo userInfo, UserInstanceDTO userInstance,
-										   EndpointDTO endpointDTO, List<LibInstallDTO> libs) {
-		checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
-		return newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), LibraryInstallDTO.class)
-				.withNotebookImage(userInstance.getImageName())
-				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
-				.withNotebookInstanceName(userInstance.getExploratoryId())
-				.withExploratoryName(userInstance.getExploratoryName())
-				.withProject(userInstance.getProject())
-				.withEndpoint(endpointDTO.getName())
-				.withLibs(libs);
-	}
-
-	@SuppressWarnings("unchecked")
-	public <T extends LibListExploratoryDTO> T newLibExploratoryList(UserInfo userInfo, UserInstanceDTO userInstance,
-	                                                                 EndpointDTO endpointDTO, String group) {
-		checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
-		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), LibListExploratoryDTO.class)
-				.withNotebookInstanceName(userInstance.getExploratoryId())
-				.withProject(userInstance.getProject())
-				.withEndpoint(endpointDTO.getName())
-				.withNotebookImage(userInstance.getImageName())
-				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
-				.withExploratoryName(userInstance.getExploratoryName())
-				.withLibCacheKey(group);
-	}
-
-	@SuppressWarnings("unchecked")
-	public <T extends LibraryInstallDTO> T newLibInstall(UserInfo userInfo, UserInstanceDTO userInstance,
-														 UserComputationalResource computationalResource,
-														 List<LibInstallDTO> libs, EndpointDTO endpointDTO) {
-		checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
-		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), LibraryInstallDTO.class)
-				.withComputationalId(computationalResource.getComputationalId())
-				.withComputationalName(computationalResource.getComputationalName())
-				.withExploratoryName(userInstance.getExploratoryName())
-				.withProject(userInstance.getProject())
-				.withEndpoint(endpointDTO.getName())
-				.withComputationalImage(computationalResource.getImageName())
-				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
-				.withLibs(libs);
-	}
-
-	@SuppressWarnings("unchecked")
-	public <T extends LibListComputationalDTO> T newLibComputationalList(UserInfo userInfo,
-	                                                                     UserInstanceDTO userInstance,
-	                                                                     UserComputationalResource
-			                                                                     computationalResource,
-	                                                                     EndpointDTO endpointDTO, String group) {
-
-		checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
-		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), LibListComputationalDTO.class)
-				.withComputationalId(computationalResource.getComputationalId())
-				.withProject(userInstance.getProject())
-				.withEndpoint(endpointDTO.getName())
-				.withComputationalImage(computationalResource.getImageName())
-				.withLibCacheKey(group)
-				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()));
-	}
-
-	@SuppressWarnings("unchecked")
-	public <T extends ComputationalBase<T>> T newComputationalCreate(UserInfo userInfo, ProjectDTO projectDTO,
-																	 UserInstanceDTO userInstance,
-																	 ComputationalCreateFormDTO form,
-																	 EndpointDTO endpointDTO) {
-		T computationalCreate;
-		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
-		switch (cloudProvider) {
-			case AZURE:
-				throw new UnsupportedOperationException("Creating dataengine service is not supported yet");
-			case AWS:
-				AwsComputationalCreateForm awsForm = (AwsComputationalCreateForm) form;
-				computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ComputationalCreateAws.class)
-						.withInstanceCount(awsForm.getInstanceCount())
-						.withMasterInstanceType(awsForm.getMasterInstanceType())
-						.withSlaveInstanceType(awsForm.getSlaveInstanceType())
-						.withSlaveInstanceSpot(awsForm.getSlaveInstanceSpot())
-						.withSlaveInstanceSpotPctPrice(awsForm.getSlaveInstanceSpotPctPrice())
-						.withVersion(awsForm.getVersion())
-						.withConfig((awsForm.getConfig()))
-						.withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
-				break;
-			case GCP:
-				GcpComputationalCreateForm gcpForm = (GcpComputationalCreateForm) form;
-				computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ComputationalCreateGcp.class)
-						.withMasterInstanceCount(gcpForm.getMasterInstanceCount())
-						.withSlaveInstanceCount(gcpForm.getSlaveInstanceCount())
-						.withPreemptibleCount(gcpForm.getPreemptibleCount())
-						.withMasterInstanceType(gcpForm.getMasterInstanceType())
-						.withSlaveInstanceType(gcpForm.getSlaveInstanceType())
-						.withVersion(gcpForm.getVersion())
-						.withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
-				break;
-
-			default:
-				throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
-		}
-
-		return computationalCreate
-				.withExploratoryName(form.getNotebookName())
-				.withComputationalName(form.getName())
-				.withNotebookTemplateName(userInstance.getTemplateName())
-				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
-				.withNotebookInstanceName(userInstance.getExploratoryId())
-				.withProject(userInstance.getProject())
-				.withTags(userInstance.getTags())
-				.withEndpoint(userInstance.getEndpoint());
-	}
-
-	@SuppressWarnings("unchecked")
-	public <T extends ComputationalBase<T>> T newComputationalCreate(UserInfo userInfo, ProjectDTO projectDTO,
-																	 UserInstanceDTO userInstance,
-																	 SparkStandaloneClusterCreateForm form,
-																	 EndpointDTO endpointDTO) {
-
-		T computationalCreate;
-		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
-		switch (cloudProvider) {
-			case AWS:
-				computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, SparkComputationalCreateAws.class)
-						.withDataEngineInstanceCount(form.getDataEngineInstanceCount())
-						.withDataEngineMasterShape(form.getDataEngineInstanceShape())
-						.withDataEngineSlaveShape(form.getDataEngineInstanceShape())
-						.withConfig(form.getConfig())
-						.withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
-				break;
-			case AZURE:
-				computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, SparkComputationalCreateAzure.class)
-						.withDataEngineInstanceCount(form.getDataEngineInstanceCount())
-						.withDataEngineMasterSize(form.getDataEngineInstanceShape())
-						.withDataEngineSlaveSize(form.getDataEngineInstanceShape())
-						.withConfig(form.getConfig())
-						.withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
-				if (settingsDAO.isAzureDataLakeEnabled()) {
-					((SparkComputationalCreateAzure) computationalCreate)
-							.withAzureUserRefreshToken(userInfo.getKeys().get(AZURE_REFRESH_TOKEN_KEY));
-				}
-
-				((SparkComputationalCreateAzure) computationalCreate)
-						.withAzureDataLakeEnabled(Boolean.toString(settingsDAO.isAzureDataLakeEnabled()));
-
-				break;
-			case GCP:
-				computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, SparkComputationalCreateGcp.class)
-						.withDataEngineInstanceCount(form.getDataEngineInstanceCount())
-						.withDataEngineMasterSize(form.getDataEngineInstanceShape())
-						.withDataEngineSlaveSize(form.getDataEngineInstanceShape())
-						.withConfig(form.getConfig())
-						.withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
-				break;
-			default:
-				throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
-		}
-
-		return computationalCreate
-				.withExploratoryName(form.getNotebookName())
-				.withComputationalName(form.getName())
-				.withNotebookTemplateName(userInstance.getTemplateName())
-				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
-				.withNotebookInstanceName(userInstance.getExploratoryId())
-				.withProject(userInstance.getProject())
-				.withTags(userInstance.getTags())
-				.withEndpoint(userInstance.getEndpoint());
-	}
-
-	@SuppressWarnings("unchecked")
-    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())
-				.withComputationalName(computationalResource.getComputationalName())
-				.withNotebookInstanceName(userInstanceDTO.getExploratoryId())
-				.withProject(userInstanceDTO.getProject())
-				.withEndpoint(userInstanceDTO.getEndpoint());
-	}
-
-	@SuppressWarnings("unchecked")
-    public <T extends ComputationalBase<T>> T newComputationalStop(String resourceCreator, UserInstanceDTO exploratory,
-                                                                   String computationalName, EndpointDTO endpointDTO) {
-        return (T) newResourceSysBaseDTO(resourceCreator, endpointDTO.getCloudProvider(), ComputationalStopDTO.class)
-                .withExploratoryName(exploratory.getExploratoryName())
-                .withComputationalName(computationalName)
-                .withNotebookInstanceName(exploratory.getExploratoryId())
-                .withApplicationName(getApplicationNameFromImage(exploratory.getImageName()))
-                .withProject(exploratory.getProject())
-                .withEndpoint(endpointDTO.getName());
-    }
-
-	@SuppressWarnings("unchecked")
-	public <T extends ComputationalBase<T>> T newComputationalStart(UserInfo userInfo, UserInstanceDTO exploratory,
-																	String computationalName, EndpointDTO endpointDTO) {
-		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ComputationalStartDTO.class)
-				.withExploratoryName(exploratory.getExploratoryName())
-				.withComputationalName(computationalName)
-				.withNotebookInstanceName(exploratory.getExploratoryId())
-				.withApplicationName(getApplicationNameFromImage(exploratory.getImageName()))
-				.withProject(exploratory.getProject())
-				.withEndpoint(endpointDTO.getName());
-	}
-
-	@SuppressWarnings("unchecked")
-	public <T extends ExploratoryImageDTO> T newExploratoryImageCreate(UserInfo userInfo, UserInstanceDTO userInstance,
-																	   String imageName, EndpointDTO endpointDTO, ProjectDTO projectDTO) {
-		checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
-		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ExploratoryImageDTO.class)
-				.withProject(userInstance.getProject())
-				.withNotebookInstanceName(userInstance.getExploratoryId())
-				.withExploratoryName(userInstance.getExploratoryName())
-				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
-				.withNotebookImage(userInstance.getImageName())
-				.withImageName(imageName)
-				.withEndpoint(userInstance.getEndpoint())
-				.withTags(userInstance.getTags())
-				.withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
-	}
-
-	@SuppressWarnings("unchecked")
-	public <T extends ComputationalBase<T>> T newComputationalCheckInactivity(UserInfo userInfo,
-																			  UserInstanceDTO exploratory,
-																			  UserComputationalResource cr, EndpointDTO endpointDTO) {
-		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ComputationalCheckInactivityDTO.class)
-				.withExploratoryName(exploratory.getExploratoryName())
-				.withComputationalName(cr.getComputationalName())
-				.withNotebookInstanceName(exploratory.getExploratoryId())
-				.withApplicationName(getApplicationNameFromImage(exploratory.getImageName()))
-				.withNotebookImageName(exploratory.getImageName())
-				.withImage(cr.getImageName())
-				.withComputationalId(cr.getComputationalId())
-				.withProject(exploratory.getProject())
-				.withEndpoint(endpointDTO.getName());
-	}
-
-
-	@SuppressWarnings("unchecked")
-	public <T extends EnvBackupDTO> T newBackupCreate(BackupFormDTO backupFormDTO, String id) {
-
-		return (T) EnvBackupDTO.builder()
-				.configFiles(backupFormDTO.getConfigFiles())
-				.certificates(backupFormDTO.getCertificates())
-				.keys(backupFormDTO.getKeys())
-				.jars(backupFormDTO.getJars())
-				.databaseBackup(backupFormDTO.isDatabaseBackup())
-				.logsBackup(backupFormDTO.isLogsBackup())
-				.id(id)
-				.build();
-	}
-
-	public ComputationalClusterConfigDTO newClusterConfigUpdate(UserInfo userInfo, UserInstanceDTO userInstanceDTO,
-																UserComputationalResource compRes,
-																List<ClusterConfig> config, EndpointDTO endpointDTO) {
-		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
-		final ComputationalClusterConfigDTO clusterConfigDTO = newResourceSysBaseDTO(userInfo.getName(), cloudProvider,
-				ComputationalClusterConfigDTO.class)
-				.withExploratoryName(userInstanceDTO.getExploratoryName())
-				.withNotebookInstanceName(userInstanceDTO.getExploratoryId())
-				.withComputationalName(compRes.getComputationalName())
-				.withApplicationName(compRes.getImageName())
-				.withProject(userInstanceDTO.getProject())
-				.withEndpoint(userInstanceDTO.getEndpoint());
-		clusterConfigDTO.setCopmutationalId(compRes.getComputationalId());
-		clusterConfigDTO.setConfig(config);
-		if (cloudProvider == AZURE && settingsDAO.isAzureDataLakeEnabled()) {
-			clusterConfigDTO.setAzureUserRefreshToken(userInfo.getKeys().get(AZURE_REFRESH_TOKEN_KEY));
-		}
-
-		return clusterConfigDTO;
-	}
-
-	public ExploratoryReconfigureSparkClusterActionDTO newClusterConfigUpdate(UserInfo userInfo,
-																			  UserInstanceDTO userInstance,
-																			  List<ClusterConfig> config,
-																			  EndpointDTO endpointDTO) {
-
-		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
-		final ExploratoryReconfigureSparkClusterActionDTO dto =
-				newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryReconfigureSparkClusterActionDTO.class)
-						.withNotebookInstanceName(userInstance.getExploratoryId())
-						.withExploratoryName(userInstance.getExploratoryName())
-						.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
-						.withNotebookImage(userInstance.getImageName())
-						.withConfig(config)
-						.withProject(userInstance.getProject())
-						.withEndpoint(userInstance.getEndpoint());
-		if (cloudProvider == AZURE && settingsDAO.isAzureDataLakeEnabled()) {
-			dto.withAzureUserRefreshToken(userInfo.getKeys().get(AZURE_REFRESH_TOKEN_KEY));
-		}
-
-		return dto;
-	}
-
-	public ExploratoryCheckInactivityAction newExploratoryCheckInactivityAction(UserInfo userInfo,
-																				UserInstanceDTO userInstance,
-																				EndpointDTO endpointDTO) {
-		final ExploratoryCheckInactivityAction dto = newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(),
-				ExploratoryCheckInactivityAction.class);
-		dto.withNotebookInstanceName(userInstance.getExploratoryId())
-				.withNotebookImage(userInstance.getImageName())
-				.withExploratoryName(userInstance.getExploratoryName())
-				.withReuploadKeyRequired(userInstance.isReuploadKeyRequired())
-				.withProject(userInstance.getProject())
-				.withEndpoint(endpointDTO.getName());
-		return dto;
-	}
-
-	public ProjectCreateDTO newProjectCreate(UserInfo userInfo, ProjectDTO projectDTO, EndpointDTO endpointDTO) {
-		return ProjectCreateDTO.builder()
-				.key(projectDTO.getKey().replace("\n", ""))
-				.name(projectDTO.getName())
-				.tag(projectDTO.getTag())
-				.endpoint(endpointDTO.getName())
-				.build()
-				.withCloudSettings(cloudSettings(userInfo.getName(), endpointDTO.getCloudProvider()));
-	}
-
-	public ProjectActionDTO newProjectAction(UserInfo userInfo, String project, EndpointDTO endpointDTO) {
-		return new ProjectActionDTO(project, endpointDTO.getName())
-				.withCloudSettings(cloudSettings(userInfo.getName(), endpointDTO.getCloudProvider()));
-	}
-
-	/**
-	 * Returns application name basing on docker image
-	 *
-	 * @param imageName docker image name
-	 * @return application name
-	 */
-	private String getApplicationNameFromImage(String imageName) {
-		if (imageName != null) {
-			int pos = imageName.indexOf('-');
-			if (pos > 0) {
-				return imageName.substring(pos + 1);
-			}
-		}
-		return "";
-	}
-
-	private void checkInappropriateCloudProviderOrElseThrowException(CloudProvider provider) {
-		if (provider != AWS && provider != AZURE && provider != GCP) {
-			throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + provider);
-		}
-	}
-}
-
-
-
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/validation/MavenLibraryNameValidator.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/validation/MavenLibraryNameValidator.java
deleted file mode 100644
index 7a40005..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/validation/MavenLibraryNameValidator.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.validation;
-
-import com.epam.dlab.backendapi.validation.annotation.LibNameValid;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-
-import javax.validation.ConstraintValidator;
-import javax.validation.ConstraintValidatorContext;
-
-@Slf4j
-public class MavenLibraryNameValidator implements ConstraintValidator<LibNameValid, String> {
-	@Override
-	public void initialize(LibNameValid libNameValid) {
-		log.trace("MavenLibraryNameValidator initialized");
-	}
-
-	@Override
-	public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
-		return StringUtils.isNotEmpty(s) && s.split(":").length == 3;
-
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/validation/SchedulerJobDTOValidator.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/validation/SchedulerJobDTOValidator.java
deleted file mode 100644
index 87dc55e..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/validation/SchedulerJobDTOValidator.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.validation;
-
-import com.epam.dlab.backendapi.validation.annotation.SchedulerJobDTOValid;
-import com.epam.dlab.dto.SchedulerJobDTO;
-
-import javax.validation.ConstraintValidator;
-import javax.validation.ConstraintValidatorContext;
-import java.util.Objects;
-
-public class SchedulerJobDTOValidator implements ConstraintValidator<SchedulerJobDTOValid, SchedulerJobDTO> {
-	@Override
-	public void initialize(SchedulerJobDTOValid schedulerJobDTOValid) {
-		//do nothing
-	}
-
-	@Override
-	public boolean isValid(SchedulerJobDTO schedulerJobDTO, ConstraintValidatorContext constraintValidatorContext) {
-		if (!schedulerJobDTO.isCheckInactivityRequired() && Objects.isNull(schedulerJobDTO.getTerminateDateTime())) {
-			return !schedulerJobDTO.getStartDaysRepeat().isEmpty() || !schedulerJobDTO.getStopDaysRepeat().isEmpty();
-		} else if (schedulerJobDTO.isCheckInactivityRequired() && Objects.isNull(schedulerJobDTO.getMaxInactivity())) {
-			constraintValidatorContext.disableDefaultConstraintViolation();
-			constraintValidatorContext.buildConstraintViolationWithTemplate("Max inactivity time should be set").addConstraintViolation();
-			return false;
-		} else {
-			return true;
-		}
-	}
-}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/validation/annotation/LibNameValid.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/validation/annotation/LibNameValid.java
deleted file mode 100644
index fb10ed2..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/validation/annotation/LibNameValid.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.validation.annotation;
-
-import com.epam.dlab.backendapi.validation.MavenLibraryNameValidator;
-
-import javax.validation.Constraint;
-import javax.validation.Payload;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Constraint(validatedBy = {MavenLibraryNameValidator.class})
-@Target({ElementType.FIELD, ElementType.PARAMETER})
-@Retention(value = RetentionPolicy.RUNTIME)
-public @interface LibNameValid {
-
-
-	String message() default "Wrong library name format. Should be <groupId>:<artifactId>:<versionId>";
-
-	Class<?>[] groups() default {};
-
-	Class<? extends Payload>[] payload() default {};
-}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/validation/annotation/SchedulerJobDTOValid.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/validation/annotation/SchedulerJobDTOValid.java
deleted file mode 100644
index 127803c..0000000
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/validation/annotation/SchedulerJobDTOValid.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.validation.annotation;
-
-import com.epam.dlab.backendapi.validation.SchedulerJobDTOValidator;
-
-import javax.validation.Constraint;
-import javax.validation.Payload;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Constraint(validatedBy = {SchedulerJobDTOValidator.class})
-@Target({ElementType.FIELD, ElementType.PARAMETER})
-@Retention(value = RetentionPolicy.RUNTIME)
-public @interface SchedulerJobDTOValid {
-
-
-	String message() default "Start/stop days or termination date is required for scheduler";
-
-	Class<?>[] groups() default {};
-
-	Class<? extends Payload>[] payload() default {};
-}
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/mongo/aws/mongo_roles.json b/services/self-service/src/main/resources/mongo/aws/mongo_roles.json
index f727854..b4eddee 100644
--- a/services/self-service/src/main/resources/mongo/aws/mongo_roles.json
+++ b/services/self-service/src/main/resources/mongo/aws/mongo_roles.json
@@ -113,7 +113,7 @@
     "type": "NOTEBOOK",
     "cloud": "AWS",
     "exploratories": [
-      "docker.dlab-deeplearning"
+      "docker.datalab-deeplearning"
     ],
     "groups": [
       "$anyuser"
@@ -125,7 +125,7 @@
     "type": "NOTEBOOK",
     "cloud": "AWS",
     "exploratories": [
-      "docker.dlab-jupyter"
+      "docker.datalab-jupyter"
     ],
     "groups": [
       "$anyuser"
@@ -137,7 +137,7 @@
     "type": "NOTEBOOK",
     "cloud": "AWS",
     "exploratories": [
-      "docker.dlab-jupyterlab"
+      "docker.datalab-jupyterlab"
     ],
     "groups": [
       "$anyuser"
@@ -149,7 +149,7 @@
     "type": "NOTEBOOK",
     "cloud": "AWS",
     "exploratories": [
-      "docker.dlab-rstudio"
+      "docker.datalab-rstudio"
     ],
     "groups": [
       "$anyuser"
@@ -161,7 +161,7 @@
     "type": "NOTEBOOK",
     "cloud": "AWS",
     "exploratories": [
-      "docker.dlab-tensor"
+      "docker.datalab-tensor"
     ],
     "groups": [
       "$anyuser"
@@ -173,7 +173,7 @@
     "type": "NOTEBOOK",
     "cloud": "AWS",
     "exploratories": [
-      "docker.dlab-zeppelin"
+      "docker.datalab-zeppelin"
     ],
     "groups": [
       "$anyuser"
@@ -185,7 +185,7 @@
     "type": "NOTEBOOK",
     "cloud": "AWS",
     "exploratories": [
-      "docker.dlab-tensor-rstudio"
+      "docker.datalab-tensor-rstudio"
     ],
     "groups": [
       "$anyuser"
@@ -197,7 +197,7 @@
     "type": "COMPUTATIONAL",
     "cloud": "AWS",
     "computationals": [
-      "docker.dlab-dataengine"
+      "docker.datalab-dataengine"
     ],
     "groups": [
       "$anyuser"
@@ -209,7 +209,7 @@
     "type": "COMPUTATIONAL",
     "cloud": "AWS",
     "computationals": [
-      "docker.dlab-dataengine-service"
+      "docker.datalab-dataengine-service"
     ],
     "groups": [
       "$anyuser"
diff --git a/services/self-service/src/main/resources/mongo/azure/mongo_roles.json b/services/self-service/src/main/resources/mongo/azure/mongo_roles.json
index 6b8f829..8b69663 100644
--- a/services/self-service/src/main/resources/mongo/azure/mongo_roles.json
+++ b/services/self-service/src/main/resources/mongo/azure/mongo_roles.json
@@ -101,7 +101,7 @@
     "type": "NOTEBOOK",
     "cloud": "AZURE",
     "exploratories": [
-      "docker.dlab-deeplearning"
+      "docker.datalab-deeplearning"
     ],
     "groups": [
       "$anyuser"
@@ -113,7 +113,7 @@
     "type": "NOTEBOOK",
     "cloud": "AZURE",
     "exploratories": [
-      "docker.dlab-jupyter"
+      "docker.datalab-jupyter"
     ],
     "groups": [
       "$anyuser"
@@ -125,7 +125,7 @@
     "type": "NOTEBOOK",
     "cloud": "AZURE",
     "exploratories": [
-      "docker.dlab-rstudio"
+      "docker.datalab-rstudio"
     ],
     "groups": [
       "$anyuser"
@@ -137,7 +137,7 @@
     "type": "NOTEBOOK",
     "cloud": "AZURE",
     "exploratories": [
-      "docker.dlab-tensor"
+      "docker.datalab-tensor"
     ],
     "groups": [
       "$anyuser"
@@ -149,7 +149,7 @@
     "type": "NOTEBOOK",
     "cloud": "AZURE",
     "exploratories": [
-      "docker.dlab-zeppelin"
+      "docker.datalab-zeppelin"
     ],
     "groups": [
       "$anyuser"
@@ -161,7 +161,7 @@
     "type": "COMPUTATIONAL",
     "cloud": "AZURE",
     "computationals": [
-      "docker.dlab-dataengine"
+      "docker.datalab-dataengine"
     ],
     "groups": [
       "$anyuser"
diff --git a/services/self-service/src/main/resources/mongo/gcp/mongo_roles.json b/services/self-service/src/main/resources/mongo/gcp/mongo_roles.json
index 11e8731..eca5101 100644
--- a/services/self-service/src/main/resources/mongo/gcp/mongo_roles.json
+++ b/services/self-service/src/main/resources/mongo/gcp/mongo_roles.json
@@ -89,7 +89,7 @@
     "type": "NOTEBOOK",
     "cloud": "GCP",
     "exploratories": [
-      "docker.dlab-deeplearning"
+      "docker.datalab-deeplearning"
     ],
     "groups": [
       "$anyuser"
@@ -101,7 +101,7 @@
     "type": "NOTEBOOK",
     "cloud": "GCP",
     "exploratories": [
-      "docker.dlab-jupyter"
+      "docker.datalab-jupyter"
     ],
     "groups": [
       "$anyuser"
@@ -113,7 +113,7 @@
     "type": "NOTEBOOK",
     "cloud": "GCP",
     "exploratories": [
-      "docker.dlab-jupyterlab"
+      "docker.datalab-jupyterlab"
     ],
     "groups": [
       "$anyuser"
@@ -125,7 +125,7 @@
     "type": "NOTEBOOK",
     "cloud": "GCP",
     "exploratories": [
-      "docker.dlab-superset"
+      "docker.datalab-superset"
     ],
     "groups": [
       "$anyuser"
@@ -137,7 +137,7 @@
     "type": "NOTEBOOK",
     "cloud": "GCP",
     "exploratories": [
-      "docker.dlab-rstudio"
+      "docker.datalab-rstudio"
     ],
     "groups": [
       "$anyuser"
@@ -149,7 +149,7 @@
     "type": "NOTEBOOK",
     "cloud": "GCP",
     "exploratories": [
-      "docker.dlab-tensor"
+      "docker.datalab-tensor"
     ],
     "groups": [
       "$anyuser"
@@ -161,7 +161,7 @@
     "type": "NOTEBOOK",
     "cloud": "GCP",
     "exploratories": [
-      "docker.dlab-tensor-rstudio"
+      "docker.datalab-tensor-rstudio"
     ],
     "groups": [
       "$anyuser"
@@ -173,7 +173,7 @@
     "type": "NOTEBOOK",
     "cloud": "GCP",
     "exploratories": [
-      "docker.dlab-zeppelin"
+      "docker.datalab-zeppelin"
     ],
     "groups": [
       "$anyuser"
@@ -185,7 +185,7 @@
     "type": "COMPUTATIONAL",
     "cloud": "GCP",
     "computationals": [
-      "docker.dlab-dataengine"
+      "docker.datalab-dataengine"
     ],
     "groups": [
       "$anyuser"
@@ -197,7 +197,7 @@
     "type": "COMPUTATIONAL",
     "cloud": "GCP",
     "computationals": [
-      "docker.dlab-dataengine-service"
+      "docker.datalab-dataengine-service"
     ],
     "groups": [
       "$anyuser"
diff --git a/services/self-service/src/main/resources/quartz.properties b/services/self-service/src/main/resources/quartz.properties
index ff0fc59..fdf33c6 100644
--- a/services/self-service/src/main/resources/quartz.properties
+++ b/services/self-service/src/main/resources/quartz.properties
@@ -20,5 +20,5 @@
 org.quartz.jobStore.collectionPrefix=scheduler
 org.quartz.jobStore.isClustered=true
 org.quartz.scheduler.instanceId=AUTO
-org.quartz.scheduler.instanceName=dlab
+org.quartz.scheduler.instanceName=datalab
 org.quartz.threadPool.threadCount=1
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/angular.json b/services/self-service/src/main/resources/webapp/angular.json
index 32b79b3..6471f31 100644
--- a/services/self-service/src/main/resources/webapp/angular.json
+++ b/services/self-service/src/main/resources/webapp/angular.json
@@ -110,11 +110,11 @@
   "defaultProject": "webapp",
   "schematics": {
     "@schematics/angular:component": {
-      "prefix": "dlab",
+      "prefix": "datalab",
       "styleext": "scss"
     },
     "@schematics/angular:directive": {
-      "prefix": "dlab"
+      "prefix": "datalab"
     }
   }
 }
diff --git a/services/self-service/src/main/resources/webapp/package-lock.json b/services/self-service/src/main/resources/webapp/package-lock.json
index f8cfcc8..78dee68 100644
--- a/services/self-service/src/main/resources/webapp/package-lock.json
+++ b/services/self-service/src/main/resources/webapp/package-lock.json
@@ -642,6 +642,335 @@
         "tslib": "^1.9.0"
       }
     },
+    "@angular/localize": {
+      "version": "9.1.12",
+      "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-9.1.12.tgz",
+      "integrity": "sha512-31OalfES+dLrxN0VXCxxtT5dWoOSlQ40KYmzMS8X+mQ20gy9eFiZK4qf3DEq3JPqRltBMdEDnwR38uGIMAu2gQ==",
+      "requires": {
+        "@babel/core": "7.8.3",
+        "glob": "7.1.2",
+        "yargs": "15.3.0"
+      },
+      "dependencies": {
+        "@babel/code-frame": {
+          "version": "7.10.4",
+          "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+          "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+          "requires": {
+            "@babel/highlight": "^7.10.4"
+          }
+        },
+        "@babel/core": {
+          "version": "7.8.3",
+          "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.3.tgz",
+          "integrity": "sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==",
+          "requires": {
+            "@babel/code-frame": "^7.8.3",
+            "@babel/generator": "^7.8.3",
+            "@babel/helpers": "^7.8.3",
+            "@babel/parser": "^7.8.3",
+            "@babel/template": "^7.8.3",
+            "@babel/traverse": "^7.8.3",
+            "@babel/types": "^7.8.3",
+            "convert-source-map": "^1.7.0",
+            "debug": "^4.1.0",
+            "gensync": "^1.0.0-beta.1",
+            "json5": "^2.1.0",
+            "lodash": "^4.17.13",
+            "resolve": "^1.3.2",
+            "semver": "^5.4.1",
+            "source-map": "^0.5.0"
+          }
+        },
+        "@babel/generator": {
+          "version": "7.11.6",
+          "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.6.tgz",
+          "integrity": "sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA==",
+          "requires": {
+            "@babel/types": "^7.11.5",
+            "jsesc": "^2.5.1",
+            "source-map": "^0.5.0"
+          }
+        },
+        "@babel/helper-function-name": {
+          "version": "7.10.4",
+          "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz",
+          "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==",
+          "requires": {
+            "@babel/helper-get-function-arity": "^7.10.4",
+            "@babel/template": "^7.10.4",
+            "@babel/types": "^7.10.4"
+          }
+        },
+        "@babel/helper-get-function-arity": {
+          "version": "7.10.4",
+          "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz",
+          "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==",
+          "requires": {
+            "@babel/types": "^7.10.4"
+          }
+        },
+        "@babel/helper-split-export-declaration": {
+          "version": "7.11.0",
+          "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz",
+          "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==",
+          "requires": {
+            "@babel/types": "^7.11.0"
+          }
+        },
+        "@babel/helpers": {
+          "version": "7.10.4",
+          "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz",
+          "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==",
+          "requires": {
+            "@babel/template": "^7.10.4",
+            "@babel/traverse": "^7.10.4",
+            "@babel/types": "^7.10.4"
+          }
+        },
+        "@babel/highlight": {
+          "version": "7.10.4",
+          "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
+          "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
+          "requires": {
+            "@babel/helper-validator-identifier": "^7.10.4",
+            "chalk": "^2.0.0",
+            "js-tokens": "^4.0.0"
+          }
+        },
+        "@babel/parser": {
+          "version": "7.11.5",
+          "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz",
+          "integrity": "sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q=="
+        },
+        "@babel/template": {
+          "version": "7.10.4",
+          "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz",
+          "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==",
+          "requires": {
+            "@babel/code-frame": "^7.10.4",
+            "@babel/parser": "^7.10.4",
+            "@babel/types": "^7.10.4"
+          }
+        },
+        "@babel/traverse": {
+          "version": "7.11.5",
+          "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.5.tgz",
+          "integrity": "sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ==",
+          "requires": {
+            "@babel/code-frame": "^7.10.4",
+            "@babel/generator": "^7.11.5",
+            "@babel/helper-function-name": "^7.10.4",
+            "@babel/helper-split-export-declaration": "^7.11.0",
+            "@babel/parser": "^7.11.5",
+            "@babel/types": "^7.11.5",
+            "debug": "^4.1.0",
+            "globals": "^11.1.0",
+            "lodash": "^4.17.19"
+          },
+          "dependencies": {
+            "lodash": {
+              "version": "4.17.20",
+              "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+              "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
+            }
+          }
+        },
+        "@babel/types": {
+          "version": "7.11.5",
+          "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz",
+          "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==",
+          "requires": {
+            "@babel/helper-validator-identifier": "^7.10.4",
+            "lodash": "^4.17.19",
+            "to-fast-properties": "^2.0.0"
+          },
+          "dependencies": {
+            "lodash": {
+              "version": "4.17.20",
+              "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+              "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
+            }
+          }
+        },
+        "ansi-regex": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
+        },
+        "ansi-styles": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+          "requires": {
+            "@types/color-name": "^1.1.1",
+            "color-convert": "^2.0.1"
+          }
+        },
+        "cliui": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+          "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+          "requires": {
+            "string-width": "^4.2.0",
+            "strip-ansi": "^6.0.0",
+            "wrap-ansi": "^6.2.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+        },
+        "convert-source-map": {
+          "version": "1.7.0",
+          "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+          "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
+          "requires": {
+            "safe-buffer": "~5.1.1"
+          }
+        },
+        "debug": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+        },
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "get-caller-file": {
+          "version": "2.0.5",
+          "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+          "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+        },
+        "json5": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
+          "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
+          "requires": {
+            "minimist": "^1.2.5"
+          }
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "minimist": {
+          "version": "1.2.5",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+          "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+        },
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        },
+        "path-exists": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
+        },
+        "require-main-filename": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+          "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
+        },
+        "string-width": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+          "requires": {
+            "ansi-regex": "^5.0.0"
+          }
+        },
+        "wrap-ansi": {
+          "version": "6.2.0",
+          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+          "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "string-width": "^4.1.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "yargs": {
+          "version": "15.3.0",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.0.tgz",
+          "integrity": "sha512-g/QCnmjgOl1YJjGsnUg2SatC7NUYEiLXJqxNOQU9qSpjzGtGXda9b+OKccr1kLTy8BN9yqEyqfq5lxlwdc13TA==",
+          "requires": {
+            "cliui": "^6.0.0",
+            "decamelize": "^1.2.0",
+            "find-up": "^4.1.0",
+            "get-caller-file": "^2.0.1",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^2.0.0",
+            "set-blocking": "^2.0.0",
+            "string-width": "^4.2.0",
+            "which-module": "^2.0.0",
+            "y18n": "^4.0.0",
+            "yargs-parser": "^18.1.0"
+          }
+        },
+        "yargs-parser": {
+          "version": "18.1.3",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+          "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+          "requires": {
+            "camelcase": "^5.0.0",
+            "decamelize": "^1.2.0"
+          }
+        }
+      }
+    },
     "@angular/material": {
       "version": "8.2.0",
       "resolved": "https://registry.npmjs.org/@angular/material/-/material-8.2.0.tgz",
@@ -942,6 +1271,11 @@
         "@babel/types": "^7.4.4"
       }
     },
+    "@babel/helper-validator-identifier": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
+      "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw=="
+    },
     "@babel/helper-wrap-function": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz",
@@ -1629,6 +1963,11 @@
         }
       }
     },
+    "@types/color-name": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
+      "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
+    },
     "@types/events": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
@@ -2014,7 +2353,6 @@
       "version": "3.2.1",
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
       "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-      "dev": true,
       "requires": {
         "color-convert": "^1.9.0"
       }
@@ -2644,7 +2982,6 @@
       "version": "1.1.8",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
       "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
-      "dev": true,
       "requires": {
         "balanced-match": "^1.0.0",
         "concat-map": "0.0.1"
@@ -2653,8 +2990,7 @@
         "balanced-match": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-          "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-          "dev": true
+          "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
         }
       }
     },
@@ -2939,8 +3275,7 @@
     "camelcase": {
       "version": "5.3.1",
       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-      "dev": true
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
     },
     "caniuse-lite": {
       "version": "1.0.30000989",
@@ -2964,7 +3299,6 @@
       "version": "2.4.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
       "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-      "dev": true,
       "requires": {
         "ansi-styles": "^3.2.1",
         "escape-string-regexp": "^1.0.5",
@@ -3277,7 +3611,6 @@
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
       "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-      "dev": true,
       "requires": {
         "color-name": "1.1.3"
       }
@@ -3285,8 +3618,7 @@
     "color-name": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-      "dev": true
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
     },
     "combined-stream": {
       "version": "1.0.8",
@@ -3344,8 +3676,7 @@
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-      "dev": true
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
     },
     "concat-stream": {
       "version": "1.6.2",
@@ -3748,8 +4079,7 @@
     "decamelize": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
-      "dev": true
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
     },
     "decode-uri-component": {
       "version": "0.2.0",
@@ -4187,8 +4517,7 @@
     "escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-      "dev": true
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
     },
     "eslint-scope": {
       "version": "4.0.3",
@@ -4929,8 +5258,7 @@
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
-      "dev": true
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
     },
     "fsevents": {
       "version": "1.2.9",
@@ -5558,6 +5886,11 @@
       "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==",
       "dev": true
     },
+    "gensync": {
+      "version": "1.0.0-beta.1",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz",
+      "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg=="
+    },
     "get-caller-file": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
@@ -5592,7 +5925,6 @@
       "version": "7.1.2",
       "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
       "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
-      "dev": true,
       "requires": {
         "fs.realpath": "^1.0.0",
         "inflight": "^1.0.4",
@@ -5626,8 +5958,7 @@
     "globals": {
       "version": "11.12.0",
       "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
-      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
-      "dev": true
+      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
     },
     "globby": {
       "version": "7.1.1",
@@ -5728,8 +6059,7 @@
     "has-flag": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-      "dev": true
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
     },
     "has-symbols": {
       "version": "1.0.0",
@@ -6090,7 +6420,6 @@
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
       "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
-      "dev": true,
       "requires": {
         "once": "^1.3.0",
         "wrappy": "1"
@@ -6099,8 +6428,7 @@
     "inherits": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-      "dev": true
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
     },
     "ini": {
       "version": "1.3.5",
@@ -6549,8 +6877,7 @@
     "js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-      "dev": true
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
     },
     "js-yaml": {
       "version": "3.13.1",
@@ -6571,8 +6898,7 @@
     "jsesc": {
       "version": "2.5.2",
       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
-      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
-      "dev": true
+      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
     },
     "json-parse-better-errors": {
       "version": "1.0.2",
@@ -6741,8 +7067,7 @@
     "lodash": {
       "version": "4.17.15",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
-      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
-      "dev": true
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
     },
     "lodash.clonedeep": {
       "version": "4.5.0",
@@ -7008,7 +7333,6 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
       "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-      "dev": true,
       "requires": {
         "brace-expansion": "^1.1.7"
       }
@@ -7582,7 +7906,6 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
       "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-      "dev": true,
       "requires": {
         "wrappy": "1"
       }
@@ -7698,7 +8021,6 @@
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
       "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
-      "dev": true,
       "requires": {
         "p-try": "^2.0.0"
       }
@@ -7730,8 +8052,7 @@
     "p-try": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-      "dev": true
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
     },
     "pacote": {
       "version": "9.5.5",
@@ -7886,8 +8207,7 @@
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
-      "dev": true
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
     },
     "path-is-inside": {
       "version": "1.0.2",
@@ -7904,8 +8224,7 @@
     "path-parse": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
-      "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
-      "dev": true
+      "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME="
     },
     "path-to-regexp": {
       "version": "0.1.7",
@@ -8609,8 +8928,7 @@
     "require-directory": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
-      "dev": true
+      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
     },
     "require-main-filename": {
       "version": "1.0.1",
@@ -8628,7 +8946,6 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz",
       "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==",
-      "dev": true,
       "requires": {
         "path-parse": "^1.0.5"
       }
@@ -8745,8 +9062,7 @@
     "safe-buffer": {
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
-      "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
-      "dev": true
+      "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
     },
     "safe-regex": {
       "version": "1.1.0",
@@ -8828,8 +9144,7 @@
     "semver": {
       "version": "5.4.1",
       "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
-      "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
-      "dev": true
+      "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
     },
     "semver-dsl": {
       "version": "1.0.1",
@@ -8934,8 +9249,7 @@
     "set-blocking": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
-      "dev": true
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
     },
     "set-value": {
       "version": "2.0.0",
@@ -9239,8 +9553,7 @@
     "source-map": {
       "version": "0.5.7",
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-      "dev": true
+      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
     },
     "source-map-loader": {
       "version": "0.2.4",
@@ -9715,7 +10028,6 @@
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
       "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-      "dev": true,
       "requires": {
         "has-flag": "^3.0.0"
       }
@@ -9902,8 +10214,7 @@
     "to-fast-properties": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
-      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
-      "dev": true
+      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
     },
     "to-object-path": {
       "version": "0.3.0",
@@ -11123,8 +11434,7 @@
     "which-module": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
-      "dev": true
+      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
     },
     "worker-farm": {
       "version": "1.7.0",
@@ -11179,8 +11489,7 @@
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-      "dev": true
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
     },
     "ws": {
       "version": "6.2.1",
@@ -11205,8 +11514,7 @@
     "y18n": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-      "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
-      "dev": true
+      "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
     },
     "yallist": {
       "version": "3.0.3",
diff --git a/services/self-service/src/main/resources/webapp/package.json b/services/self-service/src/main/resources/webapp/package.json
index 1284d50..87f060f 100644
--- a/services/self-service/src/main/resources/webapp/package.json
+++ b/services/self-service/src/main/resources/webapp/package.json
@@ -21,6 +21,7 @@
     "@angular/compiler": "^8.2.6",
     "@angular/core": "^8.2.6",
     "@angular/forms": "^8.2.6",
+    "@angular/localize": "^9.1.12",
     "@angular/material": "^8.2.0",
     "@angular/material-moment-adapter": "^8.2.0",
     "@angular/platform-browser": "^8.2.6",
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/backup-dilog/backup-dilog.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/backup-dilog/backup-dilog.component.ts
index 9bd3a25..fd7b4bd 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/backup-dilog/backup-dilog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/backup-dilog/backup-dilog.component.ts
@@ -26,7 +26,7 @@
 import { BackupService } from '../../../core/services';
 
 @Component({
-  selector: 'dlab-backup-dilog',
+  selector: 'datalab-backup-dilog',
   templateUrl: './backup-dilog.component.html',
   styleUrls: ['./backup-dilog.component.scss']
 })
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.ts
index 7f28631..6e60318 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.ts
@@ -24,7 +24,7 @@
 import { CheckUtils } from '../../../core/util';
 
 @Component({
-  selector: 'dlab-manage-env-dilog',
+  selector: 'datalab-manage-env-dilog',
   templateUrl: './manage-environment-dilog.component.html',
   styleUrls: ['./manage-environment-dilog.component.scss'],
   encapsulation: ViewEncapsulation.None
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
index 71a20db..fcee724 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
@@ -151,7 +151,7 @@
               <span ngClass="{{resource.status || ''}}" class="resource-status">{{ resource.status }}</span>
               <div class="resource-actions">
                 <span class="not-allow">
-                  <a class="start-stop-action" *ngIf="resource.image === 'docker.dlab-dataengine'">
+                  <a class="start-stop-action" *ngIf="resource.image === 'docker.datalab-dataengine'">
                     <i class="material-icons" (click)="toggleResourceAction(element, 'stop', resource)"
                       [ngClass]="{'not-allowed' : resource.status !== 'running' || selected?.length }">pause_circle_outline</i>
                   </a>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
index ab4bda7..3ee6f9f 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
@@ -300,8 +300,8 @@
             <div class="clusters-list-item" *ngFor="let cluster of notebook?.resources">
               <div class="cluster">{{cluster.computational_name}}</div>
               <div class="status" [ngClass]="{
-              'stopped': (data.action==='stop' && cluster.image==='docker.dlab-dataengine'), 'terminated': data.action === 'terminate' || (data.action==='stop' && cluster.image!=='docker.dlab-dataengine')
-              }">{{data.action  === 'stop' && cluster.image === "docker.dlab-dataengine" ? 'Stopped' : 'Terminated'}}</div>
+              'stopped': (data.action==='stop' && cluster.image==='docker.datalab-dataengine'), 'terminated': data.action === 'terminate' || (data.action==='stop' && cluster.image!=='docker.datalab-dataengine')
+              }">{{data.action  === 'stop' && cluster.image === "docker.datalab-dataengine" ? 'Stopped' : 'Terminated'}}</div>
             </div>
           </div>
         </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
index 3bd9aa8..acfeca4 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
@@ -60,7 +60,7 @@
         <i class="material-icons"></i>SSN Monitor
       </button> -->
       <button mat-raised-button class="butt env" (click)="openManageEnvironmentDialog()">
-        <i class="material-icons"></i>Manage DLab quotas
+        <i class="material-icons"></i>Manage DataLab quotas
       </button>
       <!-- <button mat-raised-button class="butt" (click)="showBackupDialog()" [disabled]="creatingBackup">
         <i class="material-icons">backup</i>Backup
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.ts
index 2791353..37a87f5 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.ts
@@ -25,7 +25,7 @@
 import { HealthStatusService } from '../../../core/services';
 
 @Component({
-  selector: 'dlab-ssn-monitor',
+  selector: 'datalab-ssn-monitor',
   templateUrl: './ssn-monitor.component.html',
   styleUrls: ['./ssn-monitor.component.scss'],
   encapsulation: ViewEncapsulation.None
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
index bd45793..183be85 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
@@ -43,7 +43,7 @@
 }
 
 @Component({
-  selector: 'dlab-project',
+  selector: 'datalab-project',
   templateUrl: './project.component.html'
 })
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts
index 189bcba..b725635 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts
@@ -28,7 +28,7 @@
 import {ConfirmationDialogComponent, ConfirmationDialogType} from '../../shared/modal-dialog/confirmation-dialog';
 
 @Component({
-  selector: 'dlab-roles',
+  selector: 'datalab-roles',
   templateUrl: './roles.component.html',
   styleUrls: ['../../resources/resources-grid/resources-grid.component.scss', './roles.component.scss']
 })
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/progress-bar.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/progress-bar.service.ts
index 7e0dabb..2bbefea 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/progress-bar.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/progress-bar.service.ts
@@ -18,7 +18,7 @@
  */
 
 import { Injectable } from '@angular/core';
-import { Subject } from "rxjs";
+import { Subject } from 'rxjs';
 
 @Injectable({
   providedIn: 'root'
diff --git a/services/self-service/src/main/resources/webapp/src/app/help/accessnotebookguide/accessnotebookguide.component.html b/services/self-service/src/main/resources/webapp/src/app/help/accessnotebookguide/accessnotebookguide.component.html
index e4a3519..9c6842a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/help/accessnotebookguide/accessnotebookguide.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/help/accessnotebookguide/accessnotebookguide.component.html
@@ -18,13 +18,13 @@
   -->
 
 <section class="guide-wrapper">
-  <h2>How to access DLAB user environment on different operation systems</h2>
+  <h2>How to access DataLab user environment on different operation systems</h2>
 
   <ul>
     <h3>How to setup tunnel to EDGE instance via SSH on Microsoft Windows</h3>
     <li>Please download PuTTY program by using <a href="https://the.earth.li/~sgtatham/putty/latest/w32/putty.exe">this link</a>.</li>
     <li>Open the PuTTY program.</li>
-    <li>In the "HostName" field enter user and IP address of your Edge Node.<br>Please use "dlab-user" for logging in.</li>
+    <li>In the "HostName" field enter user and IP address of your Edge Node.<br>Please use "datalab-user" for logging in.</li>
     <img src="./../assets/guides/1_1.png" alt="">
     <li>Open Connection &#8594; SSH &#8594; Auth tab and select a private key, corresponding to a public key, which you've specified during Initial Infrastructure setup.</li>
     <img src="./../assets/guides/1_2.png" alt="">
@@ -37,7 +37,7 @@
 
     <h3>How to access Notebook Server over SSH on Microsoft Windows</h3>
     <li>Tunnel to the Edge should be established. Run a second PuTTY session.</li>
-    <li>In the "HostName" field enter user and IP address of your Notebook instance.<br>Please use "dlab-user".</li>
+    <li>In the "HostName" field enter user and IP address of your Notebook instance.<br>Please use "datalab-user".</li>
     <img src="./../assets/guides/2_1.png" alt="">
     <li>Open Connection &#8594; SSH &#8594; Auth tab and select a private key, corresponding to a public key, which you've specified during Initial Infrastructure setup.</li>
     <img src="./../assets/guides/2_2.png" alt="">
@@ -61,14 +61,14 @@
     <li>Open terminal.</li>
     <li>Enter following command:</li>
     <div class="code-block">ssh -D 3127 USER@EDGE_IP -i PATH_TO_PRIVATE_KEY</div>
-    <li>Please use "dlab-user" for logging in .<br>Also change "EDGE_IP" and "PATH_TO_KEY" to your value.</li>
+    <li>Please use "datalab-user" for logging in .<br>Also change "EDGE_IP" and "PATH_TO_KEY" to your value.</li>
     <li>Tunnel to the Edge has been established. Do not close this terminal till you finished working with notebooks.</li>
 
     <h3>How to access Notebook Server over SSH on MacOS / Linux</h3>
     <li>Tunnel to the Edge should be established. Open new terminal.</li>
     <li>Enter following command:</li>
     <div class="code-block">ssh -o ProxyCommand='nc -x localhost:3127 %h %p' USER@NOTEBOOK_IP -i PATH_TO_PRIVATE_KEY</div>
-    <li>Please use "dlab-user" for logging in.<br>Also change "NOTEBOOK_IP" and "PATH_TO_PRIVATE_KEY" to your value.</li>
+    <li>Please use "datalab-user" for logging in.<br>Also change "NOTEBOOK_IP" and "PATH_TO_PRIVATE_KEY" to your value.</li>
     <li>Now you are connected to notebook server via SSH.</li>
   </ul>
 </section>
diff --git a/services/self-service/src/main/resources/webapp/src/app/help/publickeyguide/publickeyguide.component.html b/services/self-service/src/main/resources/webapp/src/app/help/publickeyguide/publickeyguide.component.html
index b5936b8..68ef7ee 100644
--- a/services/self-service/src/main/resources/webapp/src/app/help/publickeyguide/publickeyguide.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/help/publickeyguide/publickeyguide.component.html
@@ -32,7 +32,7 @@
     <img src="./../assets/guides/public_key.png" alt="">
     <li>You will need PRIVATE KEY to connect to your machine. Warning! You must save the private key.</li>
     <li>Click the "Save private key" button to save the private key.</li>
-    <li>PUBLIC KEY shall be uploaded using Web UI of Dlab.</li>
+    <li>PUBLIC KEY shall be uploaded using Web UI of DataLab.</li>
     <li>
       <strong>Do not use "Save public key" button for saving public key.</strong>
       To save public key in a proper format you have to copy all text from "Public key for pasting into OpenSSH
diff --git a/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.html b/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.html
index dcab0d8..44e3259 100644
--- a/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.html
@@ -17,4 +17,4 @@
   ~ under the License.
   -->
 
-<dlab-navbar></dlab-navbar>
+<datalab-navbar></datalab-navbar>
diff --git a/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.ts b/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.ts
index f3667fa..38e88f6 100644
--- a/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.ts
@@ -20,7 +20,7 @@
 import { Component, OnInit } from '@angular/core';
 
 @Component({
-  selector: 'dlab-layout',
+  selector: 'datalab-layout',
   templateUrl: './layout.component.html',
   styles: [`main { height: 100%;}`]
 })
diff --git a/services/self-service/src/main/resources/webapp/src/app/login/login.component.css b/services/self-service/src/main/resources/webapp/src/app/login/login.component.css
index a3f28fa..890b9f4 100644
--- a/services/self-service/src/main/resources/webapp/src/app/login/login.component.css
+++ b/services/self-service/src/main/resources/webapp/src/app/login/login.component.css
@@ -47,9 +47,12 @@
 }
 
 .login_page .logo {
-  display: inline-block;
+  display: flex;
+  justify-content: center;
   margin-bottom: 45px;
   cursor: default;
+  height: 250px;
+  width: 360px;
 }
 
 .login_page {
diff --git a/services/self-service/src/main/resources/webapp/src/app/login/login.component.html b/services/self-service/src/main/resources/webapp/src/app/login/login.component.html
index d87e1d1..a8e0de5 100644
--- a/services/self-service/src/main/resources/webapp/src/app/login/login.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/login/login.component.html
@@ -20,7 +20,7 @@
 <div class="login_page">
   <div class="content">
     <a class="logo">
-      <img src="assets/img/logo.png" alt="">
+      <img src="assets/svg/datalab-logo.svg" alt="">
     </a>
     <form name="form" class="form-wrap" #f="ngForm" novalidate>
       <!--
diff --git a/services/self-service/src/main/resources/webapp/src/app/login/login.component.ts b/services/self-service/src/main/resources/webapp/src/app/login/login.component.ts
index bc50072..ae5fa8f 100644
--- a/services/self-service/src/main/resources/webapp/src/app/login/login.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/login/login.component.ts
@@ -25,7 +25,7 @@
 import { DICTIONARY } from '../../dictionary/global.dictionary';
 
 @Component({
-  selector: 'dlab-login',
+  selector: 'datalab-login',
   templateUrl: 'login.component.html',
   styleUrls: ['./login.component.css']
 })
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.ts
index faf887d..b53853c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.ts
@@ -36,7 +36,7 @@
 }
 
 @Component({
-  selector: 'dlab-audit-grid',
+  selector: 'datalab-audit-grid',
   templateUrl: './audit-grid.component.html',
   styleUrls: ['./audit-grid.component.scss', '../../../resources/resources-grid/resources-grid.component.scss'],
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit.component.ts b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit.component.ts
index 14a99be..f69d45c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit.component.ts
@@ -30,20 +30,14 @@
 
 
 @Component({
-  selector: 'dlab-reporting',
+  selector: 'datalab-reporting',
   template: `
-  <div class="base-retreat">
-<!--    <dlab-toolbar (rebuildReport)="rebuildBillingReport()"-->
-<!--                  (exportReport)="exportBillingReport()"-->
-<!--                  (setRangeOption)="setRangeOption($event)">-->
-<!--    </dlab-toolbar>-->
-<!--    <mat-divider></mat-divider>-->
-<!--    <dlab-reporting-grid (filterReport)="filterReport($event)" (resetRangePicker)="resetRangePicker()"></dlab-reporting-grid>-->
-    <audit-toolbar (rebuildAudit)="rebuildAuditGrid()" (setRangeOption)="setRangeOption($event)">
-    </audit-toolbar>
-    <mat-divider></mat-divider>
-    <dlab-audit-grid (resetDateFilter)="resetDatepicker()"></dlab-audit-grid>
-  </div>
+    <div class="base-retreat">
+      <audit-toolbar (rebuildAudit)="rebuildAuditGrid()" (setRangeOption)="setRangeOption($event)">
+      </audit-toolbar>
+      <mat-divider></mat-divider>
+      <datalab-audit-grid (resetDateFilter)="resetDatepicker()"></datalab-audit-grid>
+    </div>
 
   `,
   styles: [`
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.html
index 081c711..93bdf48 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.html
@@ -39,12 +39,12 @@
             <div class="label"><span class="text"> Resource name</span></div>
             <button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()">
               <i class="material-icons">
-                <span *ngIf="filteredReportData.dlab_id.length > 0; else dlab_id_filtered">filter_list</span>
-                <ng-template #dlab_id_filtered>more_vert</ng-template>
+                <span *ngIf="filteredReportData.datalab_id.length > 0; else datalab_id_filtered">filter_list</span>
+                <ng-template #datalab_id_filtered>more_vert</ng-template>
               </i>
             </button>
           </th>
-          <td mat-cell *matCellDef="let element"><span class="table-item">{{element.dlabId}}</span></td>
+          <td mat-cell *matCellDef="let element"><span class="table-item">{{element.datalab_id}}</span></td>
           <td mat-footer-cell *matFooterCellDef class="table-footer"></td>
         </ng-container>
 
@@ -199,7 +199,7 @@
           <th mat-header-cell *matHeaderCellDef class="filter-row-item">
             <div class="input-wrapper">
               <input #nameFilter type="text" placeholder="Filter by environment name" class="form-control filter-field"
-                     [value]="filtered?.dlab_id" (input)="filteredReportData.dlab_id = $event.target['value']" (keyup)="checkFilters()"/>
+                     [value]="filtered?.datalab_id" (input)="filteredReportData.datalab_id = $event.target['value']" (keyup)="checkFilters()"/>
             </div>
           </th>
         </ng-container>
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.ts
index 29e8ed2..00175c1 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.ts
@@ -35,7 +35,7 @@
 import {take} from 'rxjs/operators';
 
 @Component({
-  selector: 'dlab-reporting-grid',
+  selector: 'datalab-reporting-grid',
   templateUrl: './reporting-grid.component.html',
   styleUrls: ['./reporting-grid.component.scss',
     '../../../resources/resources-grid/resources-grid.component.scss'],
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting.component.ts b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting.component.ts
index 2285c8c..5447c6f 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting.component.ts
@@ -29,21 +29,21 @@
 import {ProgressBarService} from '../../core/services/progress-bar.service';
 
 @Component({
-  selector: 'dlab-reporting',
+  selector: 'datalab-reporting',
   template: `
-  <div class="base-retreat">
-    <dlab-toolbar (rebuildReport)="rebuildBillingReport()"
-                  (exportReport)="exportBillingReport()"
-                  (setRangeOption)="setRangeOption($event)">
-    </dlab-toolbar>
-    <mat-divider></mat-divider>
-    <dlab-reporting-grid
-      (filterReport)="filterReport($event)"
-      (resetRangePicker)="resetRangePicker()"
-      [filteredReportData]="reportData"
-      [previousFilterData]="this.cashedFilterData"
-    ></dlab-reporting-grid>
-  </div>
+    <div class="base-retreat">
+      <datalab-toolbar (rebuildReport)="rebuildBillingReport()"
+                        (exportReport)="exportBillingReport()"
+                        (setRangeOption)="setRangeOption($event)">
+      </datalab-toolbar>
+      <mat-divider></mat-divider>
+      <datalab-reporting-grid
+        (filterReport)="filterReport($event)"
+        (resetRangePicker)="resetRangePicker()"
+        [filteredReportData]="reportData"
+        [previousFilterData]="this.cashedFilterData"
+      ></datalab-reporting-grid>
+    </div>
 
   `,
   styles: [`
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/toolbar/toolbar.component.ts b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/toolbar/toolbar.component.ts
index aa4a962..2b13c8e 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/toolbar/toolbar.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/toolbar/toolbar.component.ts
@@ -26,7 +26,7 @@
 import {GeneralEnvironmentStatus} from '../../../administration/management/management.model';
 
 @Component({
-  selector: 'dlab-toolbar',
+  selector: 'datalab-toolbar',
   templateUrl: './toolbar.component.html',
   styleUrls: ['./toolbar.component.scss'],
   encapsulation: ViewEncapsulation.None
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.html
index 03c8f03..9715f5f 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.html
@@ -113,22 +113,22 @@
         <div class="button-wrapper" [ngClass]="{'cursor-not-allow': bucketDataService.emptyFolder}">
           <i (click)="toggleBucketSelection()" class="material-icons close" *ngIf="!isSelectionOpened" [ngClass]="{'not-allowed': bucketDataService.emptyFolder}">chevron_right</i>
         </div>
-        <dlab-bucket-tree
+        <datalab-bucket-tree
           [hidden] = "!isSelectionOpened"
           (emitActiveBucket)=openBucket($event)
           [buckets]='buckets'
           [openedBucket]=this.bucketName
         >
-        </dlab-bucket-tree>
+        </datalab-bucket-tree>
       </div>
       <div class="navigation" [ngClass]="{'selection-opened': isSelectionOpened}" [hidden]="!path">
-        <dlab-folder-tree
+        <datalab-folder-tree
           (showFolderContent)=onFolderClick($event)
           (disableAll)=dissableAll($event)
           [folders]=folders
           [endpoint]=endpoint
           [cloud]="cloud"
-        > </dlab-folder-tree>
+        > </datalab-folder-tree>
       </div>
       <div class="directory" [ngClass]="{'selection-opened': isSelectionOpened}" [hidden]="!path">
         <div class="folder-item t_header">
@@ -205,7 +205,7 @@
       </div>
       <div class="loading-block" *ngIf="!path">
         <div class="uploading">
-          <p>Please wait until DLab loads bucket: <span class="strong">{{bucketName}}</span>...</p>
+          <p>Please wait until DataLab loads bucket: <span class="strong">{{bucketName}}</span>...</p>
           <mat-progress-bar mode="indeterminate"></mat-progress-bar>
         </div>
       </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.ts
index d179780..3d42053 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.ts
@@ -35,7 +35,7 @@
 import {takeUntil} from 'rxjs/operators';
 
 @Component({
-  selector: 'dlab-bucket-browser',
+  selector: 'datalab-bucket-browser',
   templateUrl: './bucket-browser.component.html',
   styleUrls: ['./bucket-browser.component.scss']
 })
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/buckets-tree/bucket-tree.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/buckets-tree/bucket-tree.component.ts
index cc8f5d8..1557917 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/buckets-tree/bucket-tree.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/buckets-tree/bucket-tree.component.ts
@@ -36,7 +36,7 @@
 }
 
 @Component({
-  selector: 'dlab-bucket-tree',
+  selector: 'datalab-bucket-tree',
   templateUrl: './bucket-tree.component.html',
   styleUrls: ['./bucket-tree.component.scss']
 })
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/folder-tree/folder-tree.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/folder-tree/folder-tree.component.ts
index ac2af44..ef1b869 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/folder-tree/folder-tree.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/folder-tree/folder-tree.component.ts
@@ -38,7 +38,7 @@
 
 
 @Component({
-  selector: 'dlab-folder-tree',
+  selector: 'datalab-folder-tree',
   templateUrl: './folder-tree.component.html',
   styleUrls: ['./folder-tree.component.scss']
 })
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.html
index e69b908..b1617c7 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.html
@@ -45,7 +45,7 @@
           </div>
           <div class="col"><span>{{ resource.template_name }}</span></div>
         </div>
-        <div class="row-wrap" *ngIf="resource.image === 'docker.dlab-dataengine-service'">
+        <div class="row-wrap" *ngIf="resource.image === 'docker.datalab-dataengine-service'">
           <div class="col">
             <p>Cluster version:</p>
           </div>
@@ -63,7 +63,7 @@
         </div>
         <div class="row-wrap">
           <div class="col"
-            *ngIf="DICTIONARY[PROVIDER].cloud_provider === 'gcp' && resource.image === 'docker.dlab-dataengine-service'; else inst">
+            *ngIf="DICTIONARY[PROVIDER].cloud_provider === 'gcp' && resource.image === 'docker.datalab-dataengine-service'; else inst">
             <p>Master instance number:</p>
           </div>
           <ng-template #inst>
@@ -77,7 +77,7 @@
           </div>
         </div>
         <div class="row-wrap"
-          *ngIf="DICTIONARY[PROVIDER].cloud_provider === 'gcp' && resource.image === 'docker.dlab-dataengine-service'">
+          *ngIf="DICTIONARY[PROVIDER].cloud_provider === 'gcp' && resource.image === 'docker.datalab-dataengine-service'">
           <div class="col">
             <p>Slave instance number:</p>
           </div>
@@ -89,7 +89,7 @@
           </div>
           <div class="col"><span>{{ resource[DICTIONARY[PROVIDER][resource.image].master_node_shape] }}</span></div>
         </div>
-        <div class="row-wrap" *ngIf="resource.image === 'docker.dlab-dataengine-service'">
+        <div class="row-wrap" *ngIf="resource.image === 'docker.datalab-dataengine-service'">
           <div class="col">
             <p>Slave instance size:</p>
           </div>
@@ -125,11 +125,11 @@
           </div>
         </div>
 
-        <div class="checkbox-group" *ngIf="resource.image === 'docker.dlab-dataengine'
+        <div class="checkbox-group" *ngIf="resource.image === 'docker.datalab-dataengine'
           && resource.status === 'running'
-          && environment.image !== 'docker.dlab-zeppelin'
-          && environment.image !== 'docker.dlab-superset'
-          && environment.image !== 'docker.dlab-jupyterlab'">
+          && environment.image !== 'docker.datalab-zeppelin'
+          && environment.image !== 'docker.datalab-superset'
+          && environment.image !== 'docker.datalab-jupyterlab'">
           <label>
             <input #configurationNode type="checkbox" (change)="selectConfiguration()" /> Cluster configurations
           </label>
@@ -145,8 +145,8 @@
             </form>
           </div>
         </div>
-        <div *ngIf="environment.image === 'docker.dlab-zeppelin' && resource.status === 'running'">
-          <small>Spark default configuration for Apache Zeppelin can not be changed from DLab UI. Currently it can be
+        <div *ngIf="environment.image === 'docker.datalab-zeppelin' && resource.status === 'running'">
+          <small>Spark default configuration for Apache Zeppelin can not be changed from DataLab UI. Currently it can be
             done directly through Apache Zeppelin interpreter menu.
             For more details please refer for Apache Zeppelin <a
               href="https://zeppelin.apache.org/docs/0.8.0/usage/interpreter/overview.html" target="_blank">official
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.ts
index e2892b5..ef5ad79 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.ts
@@ -30,7 +30,7 @@
 import {CopyPathUtils} from '../../../core/util/copyPathUtils';
 
 @Component({
-  selector: 'dlab-cluster-details',
+  selector: 'datalab-cluster-details',
   templateUrl: 'cluster-details.component.html',
   styleUrls: ['./cluster-details.component.scss']
 })
@@ -74,7 +74,7 @@
     this.upTimeSince = (this.resource.up_time) ? new Date(this.resource.up_time).toString() : '';
     this.initFormModel();
 
-    if (this.resource.image === 'docker.dlab-dataengine') this.getClusterConfiguration();
+    if (this.resource.image === 'docker.datalab-dataengine') this.getClusterConfiguration();
   }
 
   public isEllipsisActive($event): void {
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
index d8835fe..b1ca8d5 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
@@ -26,7 +26,7 @@
     <div class="content-box mat-reset">
       <form [formGroup]="resourceForm" *ngIf="clusterTypes.length && resourceForm; else placeholder">
 
-        <div class="form-wrapper" [ngClass]="{ compress: selectedImage?.image === 'docker.dlab-dataengine' }">
+        <div class="form-wrapper" [ngClass]="{ compress: selectedImage?.image === 'docker.datalab-dataengine' }">
           <div class="col">
 
             <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="clusterTypes.length === 1">
@@ -121,7 +121,7 @@
             </div>
 
             <div class="control-group" *ngIf="selectedImage?.image"
-              [hidden]="selectedImage?.image === 'docker.dlab-dataengine'">
+              [hidden]="selectedImage?.image === 'docker.datalab-dataengine'">
               <label class="label">Slave instance size</label>
               <div class="control selector-wrapper">
                 <mat-form-field>
@@ -145,7 +145,7 @@
         </div>
 
         <div class="preemptible checkbox-group control-group m-top-30 m-bott-10"
-          *ngIf="PROVIDER === 'gcp' && selectedImage?.image === 'docker.dlab-dataengine-service'">
+          *ngIf="PROVIDER === 'gcp' && selectedImage?.image === 'docker.datalab-dataengine-service'">
           <label class="label">
             <input #preemptibleNode type="checkbox" (change)="selectPreemptibleNodes($event)" />
             <span>Preemptible node</span>
@@ -188,13 +188,13 @@
 
 
         <div class="checkbox-group m-top-20"
-          [hidden]="PROVIDER === 'gcp' && selectedImage?.image === 'docker.dlab-dataengine-service'"
-          *ngIf="notebook_instance?.image !== 'docker.dlab-zeppelin'">
+          [hidden]="PROVIDER === 'gcp' && selectedImage?.image === 'docker.datalab-dataengine-service'"
+          *ngIf="notebook_instance?.image !== 'docker.datalab-zeppelin'">
           <label>
             <input #configurationNode type="checkbox" (change)="selectConfiguration()" /> Cluster configurations
           </label>
           <div class="config-link" *ngIf="(configuration?.nativeElement['checked'] || false)
-            && selectedImage?.image === 'docker.dlab-dataengine-service'
+            && selectedImage?.image === 'docker.datalab-dataengine-service'
             && PROVIDER === 'aws'">
             To view example JSON of configurations refer for <a
               href="https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-configure-apps.html" target="_blank">AWS
@@ -210,8 +210,8 @@
               parameters is not in a valid format</span>
           </div>
         </div>
-        <div *ngIf="notebook_instance?.image === 'docker.dlab-zeppelin'">
-          <small>Spark default configuration for Apache Zeppelin can not be changed from DLab UI. Currently it can be
+        <div *ngIf="notebook_instance?.image === 'docker.datalab-zeppelin'">
+          <small>Spark default configuration for Apache Zeppelin can not be changed from DataLab UI. Currently it can be
             done directly through Apache Zeppelin interpreter menu.
             For more details please refer for Apache Zeppelin <a
               href="https://zeppelin.apache.org/docs/0.8.0/usage/interpreter/overview.html" target="_blank">official
@@ -221,12 +221,12 @@
         <div class="text-center m-top-30">
           <button mat-raised-button type="button" (click)="dialogRef.close()" class="butt action">Cancel</button>
           <button mat-raised-button type="button" [disabled]="!resourceForm?.valid ||
-              (selectedImage?.image === 'docker.dlab-dataengine-service' && !resourceForm.value.shape_slave) ||
-              (selectedImage?.image === 'docker.dlab-dataengine-service' && !resourceForm.value.version)"
+              (selectedImage?.image === 'docker.datalab-dataengine-service' && !resourceForm.value.shape_slave) ||
+              (selectedImage?.image === 'docker.datalab-dataengine-service' && !resourceForm.value.version)"
             (click)="createComputationalResource(resourceForm.value)" class="butt butt-success action"
             [ngClass]="{'not-allowed': !resourceForm?.valid ||
-              (selectedImage?.image === 'docker.dlab-dataengine-service' && !resourceForm.value.shape_slave) ||
-              (selectedImage?.image === 'docker.dlab-dataengine-service' && !resourceForm.value.version) }">Create</button>
+              (selectedImage?.image === 'docker.datalab-dataengine-service' && !resourceForm.value.shape_slave) ||
+              (selectedImage?.image === 'docker.datalab-dataengine-service' && !resourceForm.value.version) }">Create</button>
         </div>
       </form>
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
index 10ad5ae..2b7f781 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
@@ -107,7 +107,7 @@
 
   public selectConfiguration() {
     if (this.configuration && this.configuration.nativeElement.checked) {
-      const template = (this.selectedImage.image === 'docker.dlab-dataengine-service')
+      const template = (this.selectedImage.image === 'docker.datalab-dataengine-service')
         ? CLUSTER_CONFIGURATION.EMR
         : CLUSTER_CONFIGURATION.SPARK;
       this.resourceForm.controls['configuration_parameters'].setValue(JSON.stringify(template, undefined, 2));
@@ -125,7 +125,7 @@
   }
 
   public isAvailableSpots(): boolean {
-    if (this.PROVIDER === 'aws' && this.selectedImage.image === 'docker.dlab-dataengine-service')
+    if (this.PROVIDER === 'aws' && this.selectedImage.image === 'docker.datalab-dataengine-service')
       return !!Object.keys(this.filterAvailableSpots()).length;
 
     return false;
@@ -170,12 +170,12 @@
       this.minInstanceNumber = this.selectedImage.limits[activeImage.total_instance_number_min];
       this.maxInstanceNumber = this.selectedImage.limits[activeImage.total_instance_number_max];
 
-      if (this.PROVIDER === 'gcp' && this.selectedImage.image === 'docker.dlab-dataengine-service') {
+      if (this.PROVIDER === 'gcp' && this.selectedImage.image === 'docker.datalab-dataengine-service') {
         this.maxInstanceNumber = this.selectedImage.limits[activeImage.total_instance_number_max] - 1;
         this.minPreemptibleInstanceNumber = this.selectedImage.limits.min_dataproc_preemptible_instance_count;
       }
 
-      if (this.PROVIDER === 'aws' && this.selectedImage.image === 'docker.dlab-dataengine-service') {
+      if (this.PROVIDER === 'aws' && this.selectedImage.image === 'docker.datalab-dataengine-service') {
         this.minSpotPrice = this.selectedImage.limits.min_emr_spot_instance_bid_pct;
         this.maxSpotPrice = this.selectedImage.limits.max_emr_spot_instance_bid_pct;
 
@@ -191,7 +191,7 @@
   //  Validation
   private validInstanceNumberRange(control) {
     if (control && control.value)
-      if (this.PROVIDER === 'gcp' && this.selectedImage.image === 'docker.dlab-dataengine-service') {
+      if (this.PROVIDER === 'gcp' && this.selectedImage.image === 'docker.datalab-dataengine-service') {
         this.validPreemptibleNumberRange();
         return control.value >= this.minInstanceNumber && control.value <= this.maxInstanceNumber ? null : { valid: false };
       } else {
@@ -286,12 +286,12 @@
     ) {
       filtered = filterShapes(key => allowed.includes(key));
       if (this.PROVIDER !== 'azure') {
-        const images = this.clusterTypes.filter(image => image.image === 'docker.dlab-dataengine');
+        const images = this.clusterTypes.filter(image => image.image === 'docker.datalab-dataengine');
         this.clusterTypes = images;
         this.selectedImage = this.clusterTypes[0];
       }
     } else if (this.notebook_instance.template_name.toLowerCase().indexOf('jupyter notebook') !== -1 &&
-      this.selectedImage.image === 'docker.dlab-dataengine-service' && this.notebook_instance.cloud_provider !== 'gcp') {
+      this.selectedImage.image === 'docker.datalab-dataengine-service' && this.notebook_instance.cloud_provider !== 'gcp') {
       filtered = filterShapes(v => v);
     } else {
       filtered = filterShapes(key => !(allowed.includes(key)));
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create.model.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create.model.ts
index ce80c52..2f6a655 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create.model.ts
@@ -31,7 +31,7 @@
   public createComputationalResource(parameters, image, env, spot, provider): Observable<{}> {
     const config = parameters.configuration_parameters ? JSON.parse(parameters.configuration_parameters) : null;
 
-    if (provider === 'aws' && image.image === 'docker.dlab-dataengine-service') {
+    if (provider === 'aws' && image.image === 'docker.datalab-dataengine-service') {
       return this.userResourceService.createComputationalResource_DataengineService({
         name: parameters.cluster_alias_name,
         emr_instance_count: parameters.instance_number,
@@ -47,7 +47,7 @@
         project: env.project,
         custom_tag: parameters.custom_tag
       }, provider);
-    } else if (provider === 'gcp' && image.image === 'docker.dlab-dataengine-service') {
+    } else if (provider === 'gcp' && image.image === 'docker.datalab-dataengine-service') {
       return this.userResourceService.createComputationalResource_DataengineService({
         template_name: image.template_name,
         image: image.image,
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/computational-resources-list.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/computational-resources-list.component.html
index 1b0a139..6430eb1 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/computational-resources-list.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/computational-resources-list.component.html
@@ -39,7 +39,7 @@
         </a>
 
         <a class="start-stop-action"
-          *ngIf="resource.image === 'docker.dlab-dataengine' && environment.status === 'running'">
+          *ngIf="resource.image === 'docker.datalab-dataengine' && environment.status === 'running'">
           <i class="material-icons" *ngIf="resource.status === 'running' || resource.status === 'stopping'"
             (click)="toggleResourceAction(resource, 'stop')"
             [ngClass]="{'not-allowed' : resource.status === 'stopping' }">pause_circle_outline</i>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
index 92362f7..7e0e63a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
@@ -27,7 +27,7 @@
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 
 @Component({
-  selector: 'dlab-ami-create-dialog',
+  selector: 'datalab-ami-create-dialog',
   templateUrl: './ami-create-dialog.component.html',
   styleUrls: ['./ami-create-dialog.component.scss']
 })
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html
index f12a3f2..ef8dafe 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html
@@ -161,7 +161,7 @@
 
         <div *ngIf="currentTemplate">
           <div class="checkbox-group"
-            *ngIf="currentTemplate?.image !== 'docker.dlab-zeppelin' && currentTemplate?.image !== 'docker.dlab-superset' && currentTemplate?.image !== 'docker.dlab-jupyterlab'">
+            *ngIf="currentTemplate?.image !== 'docker.datalab-zeppelin' && currentTemplate?.image !== 'docker.datalab-superset' && currentTemplate?.image !== 'docker.datalab-jupyterlab'">
             <label>
               <input #configurationNode type="checkbox" (change)="selectConfiguration()" /> Spark configurations
             </label>
@@ -174,8 +174,8 @@
             </div>
           </div>
 
-          <small *ngIf="currentTemplate?.image === 'docker.dlab-zeppelin'">
-            Spark default configuration for Apache Zeppelin can not be changed from DLab UI. Currently it can be
+          <small *ngIf="currentTemplate?.image === 'docker.datalab-zeppelin'">
+            Spark default configuration for Apache Zeppelin can not be changed from DataLab UI. Currently it can be
             done directly through Apache Zeppelin interpreter menu.
             For more details please refer for Apache Zeppelin <a
               href="https://zeppelin.apache.org/docs/0.8.0/usage/interpreter/overview.html" target="_blank">official
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.html
index 038fc28..d7a0c77 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.html
@@ -222,8 +222,8 @@
             </p> -->
           </div>
 
-          <div class="checkbox-group" *ngIf="notebook.image !== 'docker.dlab-zeppelin'; else not_support"
-            [hidden]="notebook.status !== 'running' || notebook.image === 'docker.dlab-superset' || notebook.image === 'docker.dlab-jupyterlab'">
+          <div class="checkbox-group" *ngIf="notebook.image !== 'docker.datalab-zeppelin'; else not_support"
+            [hidden]="notebook.status !== 'running' || notebook.image === 'docker.datalab-superset' || notebook.image === 'docker.datalab-jupyterlab'">
             <label>
               <input #configurationNode type="checkbox" (change)="selectConfiguration()" /> Cluster configurations
             </label>
@@ -241,7 +241,7 @@
           </div>
           <ng-template #not_support>
             <small [hidden]="notebook.status !== 'running'">Spark default configuration for Apache Zeppelin can not be
-              changed from DLab UI. Currently it can be done directly through Apache Zeppelin interpreter menu.
+              changed from DataLab UI. Currently it can be done directly through Apache Zeppelin interpreter menu.
               For more details please refer for Apache Zeppelin <a
                 href="https://zeppelin.apache.org/docs/0.8.0/usage/interpreter/overview.html" target="_blank">official
                 documentation</a>.
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html
index 0ac1432..e237687 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html
@@ -31,7 +31,7 @@
     <div *ngIf="notebook?.status === 'running'" class="top-wrapper">
       <div class="loading-block" *ngIf="!libs_uploaded && uploading && data.status === 'running'">
         <div class="uploading">
-          <p>Please wait until DLab loads list of available groups for your resource...</p>
+          <p>Please wait until DataLab loads list of available groups for your resource...</p>
           <img src="assets/img/gif-spinner.gif" alt="loading">
         </div>
       </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.ts
index aadfc24..5f66ec2 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.ts
@@ -26,7 +26,7 @@
 import { ManageUngitService } from '../../core/services';
 
 @Component({
-  selector: 'dlab-manage-ungit',
+  selector: 'datalab-manage-ungit',
   templateUrl: './manage-ungit.component.html',
   styleUrls: ['./manage-ungit.component.scss',
     '../exploratory/install-libraries/install-libraries.component.scss']
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.html
index c29bf51..fba2e69 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.html
@@ -157,8 +157,8 @@
           <td class="settings">
             <span #settings (click)="actions.toggle($event, settings)" class="actions"
               [ngClass]="{ 'disabled': element.status.toLowerCase() === 'creating'
-              || (element.image === 'docker.dlab-superset' && element.status !== 'running' && element.status !== 'stopped')
-              || (element.image === 'docker.dlab-jupyterlab' && element.status !== 'running' && element.status !== 'stopped') }">
+              || (element.image === 'docker.datalab-superset' && element.status !== 'running' && element.status !== 'stopped')
+              || (element.image === 'docker.datalab-jupyterlab' && element.status !== 'running' && element.status !== 'stopped') }">
             </span>
 
             <bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
@@ -198,7 +198,7 @@
                     </div>
                   </li>
                   <li
-                    *ngIf="element.status === 'running' && element.image !== 'docker.dlab-superset' && element.image !== 'docker.dlab-jupyterlab'"
+                    *ngIf="element.status === 'running' && element.image !== 'docker.datalab-superset' && element.image !== 'docker.datalab-jupyterlab'"
                     matTooltip="Only one compute can be associated with analytical tool at a time"
                     matTooltipPosition="above" [matTooltipDisabled]="!element.activeCompute"
                     [matTooltipClass]="'bucket-item-tooltip'"
@@ -221,14 +221,14 @@
                   </li>
                 </div>
                 <li (click)="exploratoryAction(element, 'ami')"
-                  *ngIf="element.status === 'running'  && element.image !== 'docker.dlab-superset' && element.image !== 'docker.dlab-jupyterlab'">
+                  *ngIf="element.status === 'running'  && element.image !== 'docker.datalab-superset' && element.image !== 'docker.datalab-jupyterlab'">
                   <div>
                     <i class="material-icons">view_module</i>
                     <span>Create AMI</span>
                   </div>
                 </li>
                 <li (click)="exploratoryAction(element, 'install')"
-                  *ngIf="element.image !== 'docker.dlab-superset' && element.image !== 'docker.dlab-jupyterlab'">
+                  *ngIf="element.image !== 'docker.datalab-superset' && element.image !== 'docker.datalab-jupyterlab'">
                   <div>
                     <i class="material-icons">developer_board</i>
                     <span>Manage libraries</span>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.ts
index 13421ee..a5d365e 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.ts
@@ -30,7 +30,7 @@
 import {BucketBrowserComponent} from './bucket-browser/bucket-browser.component';
 
 @Component({
-  selector: 'dlab-resources',
+  selector: 'datalab-resources',
   templateUrl: 'resources.component.html',
   styleUrls: ['./resources.component.scss']
 })
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.html
index a983827..857b4e7 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.html
@@ -34,14 +34,14 @@
           <mat-slide-toggle labelPosition="after" [checked]="enableSchedule" (change)="toggleSchedule($event)">
             <span *ngIf="toggleSchedule" class="hold-label">Scheduler by time</span>
           </mat-slide-toggle>
-          <div class="idle" *ngIf="destination.image !== 'docker.dlab-dataengine-service'">
+          <div class="idle" *ngIf="destination.image !== 'docker.datalab-dataengine-service'">
             <mat-slide-toggle labelPosition="before" [checked]="enableIdleTime" (change)="toggleIdleTimes($event)">
               <span *ngIf="toggleSchedule" class="hold-label">Scheduler by inactivity</span>
             </mat-slide-toggle>
           </div>
         </div>
 
-        <div class="note m-bott-10" *ngIf="destination.image !== 'docker.dlab-dataengine-service'">
+        <div class="note m-bott-10" *ngIf="destination.image !== 'docker.datalab-dataengine-service'">
           NOTE: In case of turning on inactivity time-check, your schedule
           configuration will be decommissioned.</div>
 
@@ -58,8 +58,8 @@
           </div>
         </div>
         <div class="schedule-by-time" *ngIf="!enableIdleTimeView" [ngClass]="{ hide: enableIdleTimeView, resource: destination.type === 'СOMPUTATIONAL',
-                       des: destination.image === 'docker.dlab-dataengine-service' }">
-          <div class="row-wrap" *ngIf="destination.image !== 'docker.dlab-dataengine-service'">
+                       des: destination.image === 'docker.datalab-dataengine-service' }">
+          <div class="row-wrap" *ngIf="destination.image !== 'docker.datalab-dataengine-service'">
             <div class="col-3">
               <mat-form-field>
                 <input matInput [matDatepicker]="startDate" placeholder="Choose start date" formControlName="startDate">
@@ -99,20 +99,20 @@
             </ng-template>
           </div>
 
-          <div class="row-wrap" *ngIf="destination.image !== 'docker.dlab-dataengine-service'">
+          <div class="row-wrap" *ngIf="destination.image !== 'docker.datalab-dataengine-service'">
             <div class="control-group col-3 time-range">
-              <dlab-time-picker [(pickTime)]="startTime" [label]="'Choose start time'"
-                [disable]="destination.type === 'СOMPUTATIONAL' && inherit || !enableSchedule">
+              <datalab-time-picker [(pickTime)]="startTime" [label]="'Choose start time'"
+                                    [disable]="destination.type === 'СOMPUTATIONAL' && inherit || !enableSchedule">
                 {{destination.type}}
-              </dlab-time-picker>
+              </datalab-time-picker>
             </div>
             <div class="control-group col-3 time-range">
-              <dlab-time-picker [(pickTime)]="endTime" [label]="'Choose finish time'" [disable]="destination.type === 'СOMPUTATIONAL' && inherit ||!enableSchedule">
-              </dlab-time-picker>
+              <datalab-time-picker [(pickTime)]="endTime" [label]="'Choose finish time'" [disable]="destination.type === 'СOMPUTATIONAL' && inherit ||!enableSchedule">
+              </datalab-time-picker>
             </div>
             <div class="control-group col-3 time-range" *ngIf="destination.type === 'СOMPUTATIONAL'">
-              <dlab-time-picker [(pickTime)]="terminateTime" [label]="'Choose terminate time'"
-                [disable]="!enableSchedule"></dlab-time-picker>
+              <datalab-time-picker [(pickTime)]="terminateTime" [label]="'Choose terminate time'"
+                                    [disable]="!enableSchedule"></datalab-time-picker>
             </div>
             <div *ngIf="timeReqiered" class="error term m-bott-10 mt-5"><span>At least one of time range fields
                 should be selected</span>
@@ -123,7 +123,7 @@
           </div>
 
           <div class="row-wrap"
-            *ngIf="destination.type === 'СOMPUTATIONAL' && destination.image !== 'docker.dlab-dataengine-service'">
+            *ngIf="destination.type === 'СOMPUTATIONAL' && destination.image !== 'docker.datalab-dataengine-service'">
             <div class="col-3">
               <mat-form-field class="timezone-offset">
                 <mat-select placeholder="Select timezone" [(value)]="tzOffset"
@@ -135,7 +135,7 @@
               </mat-form-field>
             </div>
           </div>
-          <div class="control-group" *ngIf="destination && destination.image !== 'docker.dlab-dataengine-service'">
+          <div class="control-group" *ngIf="destination && destination.image !== 'docker.datalab-dataengine-service'">
             <label class="label repeat" for="options">Repeat on :</label>
             <div class="days-block">
               <label>Start date:</label>
@@ -155,7 +155,7 @@
             </div>
           </div>
 
-          <div class="des-block" *ngIf="destination.image === 'docker.dlab-dataengine-service'">
+          <div class="des-block" *ngIf="destination.image === 'docker.datalab-dataengine-service'">
             <div class="row-wrap">
               <div class="col-3">
                 <mat-form-field>
@@ -166,8 +166,8 @@
                 </mat-form-field>
               </div>
               <div class="control-group col-3 time-range" *ngIf="destination.type === 'СOMPUTATIONAL'">
-                <dlab-time-picker [(pickTime)]="terminateTime" [label]="'Choose terminate time'"
-                  [disable]="!enableSchedule"></dlab-time-picker>
+                <datalab-time-picker [(pickTime)]="terminateTime" [label]="'Choose terminate time'"
+                                      [disable]="!enableSchedule"></datalab-time-picker>
               </div>
               <div class="col-3">
                 <mat-form-field class="timezone-offset">
@@ -186,7 +186,7 @@
           </div>
 
           <div class="options"
-            *ngIf="destination && allowInheritView && destination.image !== 'docker.dlab-dataengine-service'">
+            *ngIf="destination && allowInheritView && destination.image !== 'docker.datalab-dataengine-service'">
             <mat-slide-toggle labelPosition="after" [checked]="inherit" (change)="toggleInherit($event)"
               [disabled]="!enableSchedule || (!parentInherit && destination.type === 'СOMPUTATIONAL')">
               <span *ngIf="destination.type === 'EXPLORATORY'; else resourcePropagation" class="hold-label">
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.ts
index c923677..7c24887 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.ts
@@ -34,7 +34,7 @@
 import { map } from 'rxjs/operators';
 
 @Component({
-  selector: 'dlab-scheduler',
+  selector: 'datalab-scheduler',
   templateUrl: './scheduler.component.html',
   styleUrls: ['./scheduler.component.scss'],
   encapsulation: ViewEncapsulation.None
@@ -148,6 +148,7 @@
   }
 
   public toggleSchedule($event) {
+    console.log(this.tzOffset);
     this.enableSchedule = $event.checked;
     this.timeReqiered = false;
     this.allowInheritView = this.destination.type === 'СOMPUTATIONAL' || this.checkIsActiveSpark();
@@ -280,11 +281,10 @@
           params.start_days_repeat.filter(key => (this.selectedStartWeekDays[key.toLowerCase()] = true));
           params.stop_days_repeat.filter(key => (this.selectedStopWeekDays[key.toLowerCase()] = true));
           this.inherit = params.sync_start_required;
-          this.tzOffset = params.timezone_offset;
+          this.tzOffset = params.timezone_offset ? params.timezone_offset : this.tzOffset;
           this.startTime = params.start_time ? SchedulerCalculations.convertTimeFormat(params.start_time) : null;
           this.endTime = params.end_time ? SchedulerCalculations.convertTimeFormat(params.end_time) : null;
           this.formInit(params.begin_date, params.finish_date, params.terminate_datetime);
-          console.log();
           this.schedulerForm.controls.inactivityTime.setValue(params.max_inactivity || this.inactivityLimits.min);
           this.enableIdleTime = params.check_inactivity_required;
           this.considerInactivity = params.consider_inactivity || false;
@@ -318,7 +318,7 @@
   }
 
   private checkIsActiveSpark() {
-    return this.notebook.resources.length > 0 && this.notebook.resources.some(el => el.image === 'docker.dlab-dataengine'
+    return this.notebook.resources.length > 0 && this.notebook.resources.some(el => el.image === 'docker.datalab-dataengine'
       && (el.status !== 'terminated' && el.status !== 'terminating' && el.status !== 'failed'));
   }
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/service-pages/access-denied/access-denied.component.ts b/services/self-service/src/main/resources/webapp/src/app/service-pages/access-denied/access-denied.component.ts
index 5be53fd..cb290ec 100644
--- a/services/self-service/src/main/resources/webapp/src/app/service-pages/access-denied/access-denied.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/service-pages/access-denied/access-denied.component.ts
@@ -19,7 +19,7 @@
 import { Component, OnInit } from '@angular/core';
 
 @Component({
-  selector: 'dlab-access-denied',
+  selector: 'datalab-access-denied',
   template: `
     <div class="no-access-page">
       <div class="content">
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.html
index b865840..719d5a2 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.html
@@ -54,9 +54,9 @@
           <mat-list-item *ngFor="let resource of model.notebook.resources"
             [hidden]="resource.status === 'failed' || resource.status === 'terminated' || resource.status === 'terminating' || (resource.status === 'stopped' && !confirmationType)">
             <div class="cluster ellipsis">{{ resource.computational_name  }}</div>
-            <div class="status" [ngClass]="{ 'stopped': !confirmationType && resource.image === 'docker.dlab-dataengine',
-                  'terminated': resource.image === 'docker.dlab-dataengine-service' || confirmationType }">
-              {{ (!confirmationType && resource.image === 'docker.dlab-dataengine') ? 'Stopped' : 'Terminated' }}</div>
+            <div class="status" [ngClass]="{ 'stopped': !confirmationType && resource.image === 'docker.datalab-dataengine',
+                  'terminated': resource.image === 'docker.datalab-dataengine-service' || confirmationType }">
+              {{ (!confirmationType && resource.image === 'docker.datalab-dataengine') ? 'Stopped' : 'Terminated' }}</div>
             <div class="size">{{ resource[DICTIONARY[notebook.cloud_provider.toLowerCase()][resource.image].master_node_shape] }} </div>
           </mat-list-item>
         </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.ts
index 5d39c68..0a875b5 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.ts
@@ -91,7 +91,7 @@
         (resource.status !== 'failed' && resource.status !== 'terminated'
           && resource.status !== 'terminating' && resource.status !== 'stopped'))
       .forEach(resource => {
-        (resource.image === 'docker.dlab-dataengine') ? this.dataengines.push(resource) : this.dataengineServices.push(resource);
+        (resource.image === 'docker.datalab-dataengine') ? this.dataengines.push(resource) : this.dataengineServices.push(resource);
       });
   }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
index a192d2b..845e76b 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
@@ -28,7 +28,7 @@
     </button>
 
     <a [routerLink]="['/resources_list']" class="navbar-logo">
-      <img src="assets/img/logo-nav.png" alt="">
+      <img src="assets/svg/logo.svg" alt="">
     </a>
   </div>
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.scss b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.scss
index f3bdfb7..86480bd 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.scss
@@ -36,7 +36,7 @@
     align-items: center;
 
     .navbar-logo {
-      width: 65px;
+      width: 85px;
       align-self: center;
       margin-left: 10px;
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts
index 55df3a2..73dd5d9 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts
@@ -48,7 +48,7 @@
   totalQuotaUsed: number;
 }
 @Component({
-  selector: 'dlab-navbar',
+  selector: 'datalab-navbar',
   templateUrl: 'navbar.component.html',
   styleUrls: ['./navbar.component.scss'],
   animations: [trigger('fadeAnimation', [
@@ -254,45 +254,45 @@
   private selectAlert(type: string, total_quota?: number, exideedProjects?: string[], informProjects?: string[]): string {
     const alerts = {
       total_quota_and_project_inform_and_exceed: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br />
-          DLab cloud infrastructure usage quota has been used for <span class="strong">${total_quota}%</span>.
+          DataLab cloud infrastructure usage quota has been used for <span class="strong">${total_quota}%</span>.
           Once quota is depleted all your analytical environment will be stopped.<br /><br />
           Quota associated with project(s) <span class="strong">${exideedProjects.join(', ')}</span> has been exceeded. All your analytical environment will be stopped.<br /><br />
           Quota associated with project(s) <span class="strong">${informProjects.join(', ')}</span> has been used over <span class="strong">${this.quotesLimit}%</span>.
           If quota is depleted all your analytical environment will be stopped.<br /><br />
-          To proceed working with environment you'll have to request increase of quota from DLab administrator. `,
+          To proceed working with environment you'll have to request increase of quota from DataLab administrator. `,
 
       total_quota_and_project_exceed: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br />
-          DLab cloud infrastructure usage quota has been used for <span class="strong">${total_quota}%</span>.
+          DataLab cloud infrastructure usage quota has been used for <span class="strong">${total_quota}%</span>.
           Once quota is depleted all your analytical environment will be stopped.<br /><br />
           Quota associated with project(s) <span class="strong">${exideedProjects.join(', ')}</span> has been exceeded. All your analytical environment will be stopped.<br /><br />
-          To proceed working with environment you'll have to request increase of quota from DLab administrator. `,
+          To proceed working with environment you'll have to request increase of quota from DataLab administrator. `,
 
       project_inform_and_exceed: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br />
-          DLab cloud infrastructure usage quota associated with project(s) <span class="strong">${exideedProjects.join(', ')}</span> has been exceeded. All your analytical environment will be stopped.<br /><br />
+          DataLab cloud infrastructure usage quota associated with project(s) <span class="strong">${exideedProjects.join(', ')}</span> has been exceeded. All your analytical environment will be stopped.<br /><br />
           Quota associated with project(s) <span class="strong">${informProjects.join(', ')}</span> has been used over <span class="strong">${this.quotesLimit}%</span>.
           If quota is depleted all your analytical environment will be stopped.<br /><br />
-          To proceed working with environment, request increase of project quota from DLab administrator.`,
+          To proceed working with environment, request increase of project quota from DataLab administrator.`,
       project_exceed: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br />
-          DLab cloud infrastructure usage quota associated with project(s) <span class="strong">${exideedProjects.join(', ')}</span> has been exceeded.
+          DataLab cloud infrastructure usage quota associated with project(s) <span class="strong">${exideedProjects.join(', ')}</span> has been exceeded.
           All your analytical environment will be stopped.<br /><br />
           To proceed working with environment,
-          request increase of project(s) quota from DLab administrator.`,
+          request increase of project(s) quota from DataLab administrator.`,
       total_exceed: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br />
-          DLab cloud infrastructure usage quota has been exceeded.
+          DataLab cloud infrastructure usage quota has been exceeded.
           All your analytical environment will be stopped.<br /><br />
           To proceed working with environment,
-          request increase application quota from DLab administrator.`,
+          request increase application quota from DataLab administrator.`,
       project_quota: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br />
           Cloud infrastructure usage quota associated with project(s) <span class="strong">${informProjects.join(', ')}</span> has been used over <span class="strong">${this.quotesLimit}%</span>.
           Once quota is depleted all your analytical environment will be stopped.<br /><br />
-          To proceed working with environment you'll have to request increase of project(s) quota from DLab administrator.`,
+          To proceed working with environment you'll have to request increase of project(s) quota from DataLab administrator.`,
       total_quota: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br />
-          DLab cloud infrastructure usage quota has been used for <span class="strong">${total_quota}%</span>.
+          DataLab cloud infrastructure usage quota has been used for <span class="strong">${total_quota}%</span>.
           Once quota is depleted all your analytical environment will be stopped.<br /><br />
-          To proceed working with environment you'll have to request increase of total quota from DLab administrator. `,
+          To proceed working with environment you'll have to request increase of total quota from DataLab administrator. `,
       permissions: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br />
           Currently, you are not assigned to any project. To start working with the environment
-          request permission from DLab administrator.`
+          request permission from DataLab administrator.`
     };
 
     return alerts[type];
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/time-picker/time-picker.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/time-picker/time-picker.component.ts
index 020872e..a58826a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/time-picker/time-picker.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/time-picker/time-picker.component.ts
@@ -22,9 +22,9 @@
 
 import { CLOCK_TYPE, TimeFormat } from './ticker.component';
 type TimeFormatAlias = TimeFormat;
-     
+
 @Component({
-  selector: 'dlab-time-picker',
+  selector: 'datalab-time-picker',
   template: `
     <div class="time-picker">
       <mat-form-field class="time-select">
@@ -58,7 +58,7 @@
         time: {
           hour: this.pickTime ? this.pickTime.hour : 0,
           minute: this.pickTime ? this.pickTime.minute : 0,
-          meridiem: this.pickTime ? this.pickTime.meridiem : 'AM' 
+          meridiem: this.pickTime ? this.pickTime.meridiem : 'AM'
         }
       }
     });
diff --git a/services/self-service/src/main/resources/webapp/src/app/swagger/swagger.component.ts b/services/self-service/src/main/resources/webapp/src/app/swagger/swagger.component.ts
index 5c3c612..2d2f6e5 100644
--- a/services/self-service/src/main/resources/webapp/src/app/swagger/swagger.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/swagger/swagger.component.ts
@@ -24,7 +24,7 @@
 declare const SwaggerUIBundle: any;
 
 @Component({
-  selector: 'dlab-swagger',
+  selector: 'datalab-swagger',
   templateUrl: './swagger.component.html',
   styleUrls: ['./swagger.component.scss']
 })
diff --git a/services/self-service/src/main/resources/webapp/src/app/webterminal/webterminal.component.ts b/services/self-service/src/main/resources/webapp/src/app/webterminal/webterminal.component.ts
index 7f796d1..d92c263 100644
--- a/services/self-service/src/main/resources/webapp/src/app/webterminal/webterminal.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/webterminal/webterminal.component.ts
@@ -31,7 +31,7 @@
 import { FileUtils } from '../core/util';
 
 @Component({
-  selector: 'dlab-webterminal',
+  selector: 'datalab-webterminal',
   templateUrl: './webterminal.component.html',
   styleUrls: ['./webterminal.component.scss'],
   encapsulation: ViewEncapsulation.None
@@ -62,7 +62,7 @@
     const url = environment.production ? window.location.origin : API_URL;
     const tunnel = new Guacamole.HTTPTunnel(
       `${url}/api/tunnel`, false,
-      { 'DLab-Authorization': `Bearer ${this.storageService.getToken()}` }
+      { 'DataLab-Authorization': `Bearer ${this.storageService.getToken()}` }
     );
 
     const guac = new Guacamole.Client(tunnel);
diff --git a/services/self-service/src/main/resources/webapp/src/assets/data.json b/services/self-service/src/main/resources/webapp/src/assets/data.json
index cb8e3d1..d8bbff7 100644
--- a/services/self-service/src/main/resources/webapp/src/assets/data.json
+++ b/services/self-service/src/main/resources/webapp/src/assets/data.json
@@ -56,7 +56,7 @@
             ]
           }
         ],
-        "image": "docker.dlab-dataengine-service",
+        "image": "docker.datalab-dataengine-service",
         "image_type": "COMPUTATIONAL",
         "template_name": "EMR cluster",
         "environment_type": "computational",
@@ -142,7 +142,7 @@
       {
         "description": "Spark standalone cluster",
         "templates": [],
-        "image": "docker.dlab-dataengine",
+        "image": "docker.datalab-dataengine",
         "image_type": "COMPUTATIONAL",
         "template_name": "Spark cluster",
         "environment_type": "computational",
diff --git a/services/self-service/src/main/resources/webapp/src/assets/endpoint-api.json b/services/self-service/src/main/resources/webapp/src/assets/endpoint-api.json
index 73d6eb5..57adc16 100644
--- a/services/self-service/src/main/resources/webapp/src/assets/endpoint-api.json
+++ b/services/self-service/src/main/resources/webapp/src/assets/endpoint-api.json
@@ -7,9 +7,9 @@
   }
   ],
   "info": {
-    "description": "DLab cloud endpoint API",
+    "description": "DataLab cloud endpoint API",
     "version": "0.0.1",
-    "title": "DLab cloud endpoint API",
+    "title": "DataLab cloud endpoint API",
     "contact": {
       "email": "bohdan_hliva@epam.com"
     },
diff --git a/services/self-service/src/main/resources/webapp/src/assets/styles/app-loading.scss b/services/self-service/src/main/resources/webapp/src/assets/styles/app-loading.scss
index 6fb034b..aa43b4b 100644
--- a/services/self-service/src/main/resources/webapp/src/assets/styles/app-loading.scss
+++ b/services/self-service/src/main/resources/webapp/src/assets/styles/app-loading.scss
@@ -1,88 +1,69 @@
-/*!
- * 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.
- */
-
-body,
-html {
-  height: 100%;
-}
-
-.app-loading {
-  position: relative;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  height: 100%;
-}
-
-.app-loading .spinner {
-  height: 200px;
-  width: 200px;
-  animation: rotate 2s linear infinite;
-  transform-origin: center center;
-  position: absolute;
-  top: calc(50% - 100px);
-  left: calc(50% - 100px);
-  margin: 0;
-}
-
-.app-loading .spinner .path {
-  stroke-dasharray: 20, 200;
-  stroke-dashoffset: 0;
-  animation: dash 1.5s ease-in-out infinite;
-  stroke-linecap: round;
-  stroke: #35afd5;
-}
-
-@keyframes rotate {
-  100% {
-    transform: rotate(360deg);
-  }
-}
-
-@keyframes dash {
-  0% {
-    stroke-dasharray: 1, 200;
-    stroke-dashoffset: 0;
-  }
-
-  50% {
-    stroke-dasharray: 89, 200;
-    stroke-dashoffset: -35px;
-  }
-
-  100% {
-    stroke-dasharray: 89, 200;
-    stroke-dashoffset: -124px;
-  }
-}
-
-
-.app-loading {
-  .logo {
-    width: 100px;
-    height: 100px;
-    // background: url(../img/logo.png);
-    background-size: cover;
-  }
-}
-
+//body,
+//html {
+//  height: 100%;
+//}
+//
+//.app-loading {
+//  position: relative;
+//  display: flex;
+//  flex-direction: column;
+//  align-items: center;
+//  justify-content: center;
+//  height: 100%;
+//}
+//
+//.app-loading .spinner {
+//  height: 300px;
+//  width: 225px;
+//  animation: rotate 2s linear infinite;
+//  transform-origin: center center;
+//  position: absolute;
+//  top: calc(50% - 125px);
+//  left: calc(50% - 125px);
+//  margin: 0;
+//}
+//
+//.app-loading .spinner .path {
+//  stroke-dasharray: 20, 200;
+//  stroke-dashoffset: 0;
+//  animation: dash 1.5s ease-in-out infinite;
+//  stroke-linecap: round;
+//  stroke: #35afd5;
+//}
+//
+//@keyframes rotate {
+//  100% {
+//    transform: rotate(360deg);
+//  }
+//}
+//
+//@keyframes dash {
+//  0% {
+//    stroke-dasharray: 1, 200;
+//    stroke-dashoffset: 0;
+//  }
+//
+//  50% {
+//    stroke-dasharray: 89, 200;
+//    stroke-dashoffset: -35px;
+//  }
+//
+//  100% {
+//    stroke-dasharray: 89, 200;
+//    stroke-dashoffset: -124px;
+//  }
+//}
+//
+//
+//.app-loading {
+//  .logo {
+//    width: 150px;
+//    height: 100px;
+//    // background: url(../img/logo.png);
+//    background-size: cover;
+//  }
+//}
+//
 .nav-bar .mat-progress-bar {
   position: absolute;
   height: 2px;
diff --git a/services/self-service/src/main/resources/webapp/src/assets/svg/datalab-logo.svg b/services/self-service/src/main/resources/webapp/src/assets/svg/datalab-logo.svg
new file mode 100644
index 0000000..f9ebb29
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/assets/svg/datalab-logo.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="309px" height="152px" viewBox="0 0 309 152" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>Group</title>
+    <g id="Page-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Artboard-Copy" transform="translate(-100.000000, -6.000000)" fill="#35AFD5" fill-rule="nonzero">
+            <g id="Group" transform="translate(100.000000, 6.000000)">
+                <path d="M48,0 L48,50.304 L48.040916,55.668891 L47.950033,55.677562 L46.6386939,55.8175213 L45.9255692,55.900871 L45.8143969,55.915542 C23.9652352,58.951769 7.5,77.7148504 7.5,99.9895207 C7.5,124.566192 27.4233286,144.489521 52,144.489521 C63.7945578,144.489521 74.850976,139.884216 83.1068414,131.811186 L83.5172913,131.404651 L88.4750135,136.34641 C78.8766784,145.975749 65.8707068,151.489521 52,151.489521 C23.5573354,151.489521 0.5,128.432185 0.5,99.9895207 C0.5,75.5349665 17.6438798,54.7411444 40.9999076,49.6668368 L41,7 L32,7 L32,0 L48,0 Z M165.725133,87 C180.659525,87 185.571785,99.997962 185.668537,106.310769 L185.67,106.5 L185.67,125.401152 L179.21943,125.401152 L179.21943,120.31094 C176.401939,123.454894 171.804981,126 165.725133,126 C155.27076,126 146.67,117.466411 146.67,106.537428 C146.67,95.6084453 155.27076,87 165.725133,87 Z M100.725133,87 C115.659525,87 120.571785,99.997962 120.668537,106.310769 L120.67,106.5 L120.67,125.401152 L114.21943,125.401152 L114.21943,120.31094 C111.401939,123.454894 106.804981,126 100.725133,126 C90.2707605,126 81.67,117.466411 81.67,106.537428 C81.67,95.6084453 90.2707605,87 100.725133,87 Z M276.194715,74 L276.194715,92.030303 C279.160494,89.012987 283.683308,86.6580087 289.614867,86.6580087 C300.06924,86.6580087 308.67,95.1212121 308.67,105.865801 C308.67,116.61039 300.06924,125 289.614867,125 C281.830928,125 269.921189,119.162503 269.673914,106.275116 L269.67,105.865801 L269.67,74 L276.194715,74 Z M200.895734,74 L200.895734,118.373723 L226.67,118.373723 L226.67,125 L193.67,125 L193.67,74 L200.895734,74 Z M245.725133,86 C260.659525,86 265.571785,98.997962 265.668537,105.310769 L265.67,105.5 L265.67,124.401152 L259.21943,124.401152 L259.21943,119.31094 C256.401939,122.454894 251.804981,125 245.725133,125 C235.27076,125 226.67,116.466411 226.67,105.537428 C226.67,94.6084453 235.27076,86 245.725133,86 Z M52.76,74.31 C67.412,74.31 78.438,85.336 78.438,99.544 C78.438,113.68318 67.6314174,124.776209 53.1984648,124.996656 L52.76,125 L35,125 L35,74.31 L52.76,74.31 Z M135.658,77 L135.658,87.286 L145.574,87.286 L145.574,93.058 L135.658,93.058 L135.658,112.668 C135.658,117.45432 138.429714,118.900369 141.814049,118.956296 L142.022,118.958 L145.574,118.958 L145.574,124.73 L141.948,124.73 C134.582319,124.73 129.372756,121.136469 129.223301,113.028631 L129.22,112.668 L129.22,93.058 L123.67,93.058 L123.67,87.286 L129.22,87.286 L129.22,77 L135.658,77 Z M166.095856,93.1381958 C158.681407,93.1381958 153.046426,99.0518234 153.046426,106.537428 C153.046426,114.023033 158.681407,119.93666 166.095856,119.93666 C173.658593,119.93666 179.367719,114.097889 179.367719,106.537428 C179.367719,99.0518234 173.584449,93.1381958 166.095856,93.1381958 Z M101.095856,93.1381958 C93.6814068,93.1381958 88.0464259,99.0518234 88.0464259,106.537428 C88.0464259,114.023033 93.6814068,119.93666 101.095856,119.93666 C108.658593,119.93666 114.367719,114.097889 114.367719,106.537428 C114.367719,99.0518234 108.584449,93.1381958 101.095856,93.1381958 Z M289.244144,92.6926407 C281.755551,92.6926407 275.972281,98.5064935 275.972281,105.865801 C275.972281,113.298701 281.681407,119.038961 289.244144,119.038961 C296.658593,119.038961 302.293574,113.225108 302.293574,105.865801 C302.293574,98.5064935 296.658593,92.6926407 289.244144,92.6926407 Z M246.095856,92.1381958 C238.681407,92.1381958 233.046426,98.0518234 233.046426,105.537428 C233.046426,113.023033 238.681407,118.93666 246.095856,118.93666 C253.658593,118.93666 259.367719,113.097889 259.367719,105.537428 C259.367719,98.0518234 253.584449,92.1381958 246.095856,92.1381958 Z M52.464,80.896 L42.178,80.896 L42.178,118.414 L52.316,118.414 C63.416,118.414 71.26,110.2 71.26,99.692 C71.26,89.036 63.194,80.896 52.464,80.896 Z M72,0 L72,7 L62.9994923,7 L63.0003609,49.6793321 C72.3934241,51.7252087 80.9885914,56.3662817 87.8723853,63.0520566 L88.3188454,63.4909316 L83.3817065,68.4532556 C76.4855783,61.5921271 67.5443496,57.1475703 57.8192825,55.8771804 L57.1166971,55.791461 L56.0381427,55.6853811 L55.9874923,55.6803995 L55.9994923,50.98 L56,0 L72,0 Z" id="Combined-Shape"></path>
+            </g>
+        </g>
+    </g>
+</svg>
diff --git a/services/self-service/src/main/resources/webapp/src/assets/svg/logo.svg b/services/self-service/src/main/resources/webapp/src/assets/svg/logo.svg
index b0b4da0..cf71a7c 100644
--- a/services/self-service/src/main/resources/webapp/src/assets/svg/logo.svg
+++ b/services/self-service/src/main/resources/webapp/src/assets/svg/logo.svg
@@ -1,3 +1,7 @@
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 140.5 47.1" style="enable-background:new 0 0 140.5 47.1;" xml:space="preserve">
-    <path fill="#35AFD5" d="M0.9,46C0.3,45.4,0,44.6,0,43.7V3.1c0-0.8,0.3-1.7,0.9-2.2C1.5,0.3,2.3,0,3.1,0H14c4.2-0.1,8.3,1,12,3 c3.5,1.9,6.3,4.8,8.2,8.3c2,3.7,3,7.9,3,12.1c0.1,4.2-0.9,8.4-2.9,12.1c-1.9,3.5-4.8,6.4-8.3,8.3c-3.7,2-7.8,3.1-12.1,3H3.1 C2.3,46.9,1.5,46.6,0.9,46z M14,41.3c3.1,0.1,6.2-0.7,8.9-2.3c2.6-1.5,4.7-3.7,6.1-6.4c1.5-2.9,2.2-6,2.2-9.3 c0.1-3.2-0.7-6.4-2.2-9.2c-1.4-2.7-3.5-4.9-6.1-6.4c-2.7-1.5-5.8-2.3-8.9-2.3H6.2v35.8H14z M41.8,46.2C41.3,45.6,41,44.8,41,44V3.4 c0-0.8,0.3-1.6,0.9-2.2c0.6-0.6,1.3-0.9,2.1-0.9c1.7,0,3.1,1.3,3.1,3c0,0,0,0.1,0,0.1v37.5h21.8c1.7,0,3.1,1.4,3.1,3.1 c0,1.7-1.4,3.1-3.1,3.1c0,0,0,0,0,0H44C43.2,47.1,42.4,46.8,41.8,46.2z M96.2,16c2.5,1.4,4.5,3.5,5.9,6c1.5,2.6,2.2,5.5,2.2,8.5 v13.4c0,1.7-1.4,3.1-3.1,3.1c-1.7,0-3.1-1.4-3.1-3.1v-2.2c-4.8,5.7-13,7.1-19.4,3.3c-2.4-1.5-4.3-3.5-5.5-6c-1.4-2.6-2-5.5-2-8.5 c0-3,0.7-5.9,2.1-8.4c1.4-2.5,3.5-4.6,6-6c2.6-1.5,5.5-2.2,8.4-2.2C90.7,13.8,93.6,14.5,96.2,16z M93.2,40.2c1.6-1,2.9-2.3,3.8-4 c0.9-1.8,1.4-3.7,1.4-5.7c0-2-0.5-4-1.4-5.8c-2.8-5.1-9.2-7-14.4-4.2c-0.1,0.1-0.2,0.1-0.3,0.2c-1.6,1-2.9,2.3-3.8,4 c-1,1.8-1.4,3.8-1.4,5.8c0,2,0.5,4,1.4,5.7c0.9,1.7,2.2,3,3.8,4C85.7,42.2,89.8,42.2,93.2,40.2L93.2,40.2z M132.9,16 c2.4,1.5,4.3,3.5,5.5,6c1.4,2.6,2,5.5,2,8.5c0,3-0.7,5.9-2.2,8.5c-1.4,2.5-3.5,4.6-6,6c-2.6,1.5-5.5,2.2-8.4,2.2 c-5.9,0.1-11.4-3.1-14.3-8.2c-1.5-2.6-2.2-5.5-2.2-8.5V3.1c0-0.8,0.3-1.6,0.9-2.2c1.3-1.1,3.2-1.1,4.4,0c0.6,0.6,0.9,1.4,0.8,2.2 v16.2C118.3,13.5,126.5,12.1,132.9,16z M129.3,40.3c1.6-1,2.9-2.4,3.8-4c1-1.8,1.4-3.8,1.4-5.8c0-2-0.5-4-1.4-5.7 c-0.9-1.7-2.2-3-3.8-4c-4.9-3-11.4-1.4-14.4,3.5c-0.1,0.2-0.2,0.3-0.3,0.5c-0.9,1.8-1.4,3.7-1.4,5.7c0,2,0.4,4,1.4,5.8 c2.8,5.1,9.2,7,14.4,4.2C129.1,40.4,129.2,40.3,129.3,40.3z M41,0.1h6.2v5.3H41V0.1z M0,0h6.1v5.3H0V0z M0,41.5h6.1v5.3H0V41.5z  M65.9,40.9H72v6.2h-6.1V40.9z M41,41.9h3.5v5.2H41V41.9z M98.2,41.3h6.1v5.6h-6.1V41.3z M107.4,0h6.1v5.4h-6.1V0z" />
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="274px" height="52px" viewBox="0 0 274 52" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>Combined Shape</title>
+    <g id="Page-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <path d="M130.725133,13 C145.810378,13 150.67,26.2618732 150.67,32.5 L150.67,32.5 L150.67,51.4011516 L144.21943,51.4011516 L144.21943,46.3109405 C141.401939,49.4548944 136.804981,52 130.725133,52 C120.27076,52 111.67,43.4664107 111.67,32.537428 C111.67,21.6084453 120.27076,13 130.725133,13 Z M65.7251331,13 C80.8103777,13 85.67,26.2618732 85.67,32.5 L85.67,32.5 L85.67,51.4011516 L79.2194297,51.4011516 L79.2194297,46.3109405 C76.4019392,49.4548944 71.804981,52 65.7251331,52 C55.2707605,52 46.67,43.4664107 46.67,32.537428 C46.67,21.6084453 55.2707605,13 65.7251331,13 Z M241.524715,0 L241.524715,18.030303 C244.490494,15.012987 249.013308,12.6580087 254.944867,12.6580087 C265.39924,12.6580087 274,21.1212121 274,31.8658009 C274,42.6103896 265.39924,51 254.944867,51 C247.078992,51 235,45.038961 235,31.8658009 L235,31.8658009 L235,0 L241.524715,0 Z M166.225734,0 L166.225734,44.3737226 L192,44.3737226 L192,51 L159,51 L159,0 L166.225734,0 Z M211.055133,12 C226.140378,12 231,25.2618732 231,31.5 L231,31.5 L231,50.4011516 L224.54943,50.4011516 L224.54943,45.3109405 C221.731939,48.4548944 217.134981,51 211.055133,51 C200.60076,51 192,42.4664107 192,31.537428 C192,20.6084453 200.60076,12 211.055133,12 Z M17.76,0.31 C32.412,0.31 43.438,11.336 43.438,25.544 C43.438,39.826 32.412,51 17.76,51 L17.76,51 L4.97379915e-14,51 L4.97379915e-14,0.31 Z M100.658,3 L100.658,13.286 L110.574,13.286 L110.574,19.058 L100.658,19.058 L100.658,38.668 C100.658,43.552 103.544,44.958 107.022,44.958 L107.022,44.958 L110.574,44.958 L110.574,50.73 L106.948,50.73 C99.474,50.73 94.22,47.03 94.22,38.668 L94.22,38.668 L94.22,19.058 L88.67,19.058 L88.67,13.286 L94.22,13.286 L94.22,3 L100.658,3 Z M131.095856,19.1381958 C123.681407,19.1381958 118.046426,25.0518234 118.046426,32.537428 C118.046426,40.0230326 123.681407,45.9366603 131.095856,45.9366603 C138.658593,45.9366603 144.367719,40.0978887 144.367719,32.537428 C144.367719,25.0518234 138.584449,19.1381958 131.095856,19.1381958 Z M66.0958555,19.1381958 C58.6814068,19.1381958 53.0464259,25.0518234 53.0464259,32.537428 C53.0464259,40.0230326 58.6814068,45.9366603 66.0958555,45.9366603 C73.6585932,45.9366603 79.3677186,40.0978887 79.3677186,32.537428 C79.3677186,25.0518234 73.5844487,19.1381958 66.0958555,19.1381958 Z M254.574144,18.6926407 C247.085551,18.6926407 241.302281,24.5064935 241.302281,31.8658009 C241.302281,39.2987013 247.011407,45.038961 254.574144,45.038961 C261.988593,45.038961 267.623574,39.2251082 267.623574,31.8658009 C267.623574,24.5064935 261.988593,18.6926407 254.574144,18.6926407 Z M211.425856,18.1381958 C204.011407,18.1381958 198.376426,24.0518234 198.376426,31.537428 C198.376426,39.0230326 204.011407,44.9366603 211.425856,44.9366603 C218.988593,44.9366603 224.697719,39.0978887 224.697719,31.537428 C224.697719,24.0518234 218.914449,18.1381958 211.425856,18.1381958 Z M17.464,6.896 L7.178,6.896 L7.178,44.414 L17.316,44.414 C28.416,44.414 36.26,36.2 36.26,25.692 C36.26,15.036 28.194,6.896 17.464,6.896 L17.464,6.896 Z" id="Combined-Shape" fill="#35AFD5" fill-rule="nonzero"></path>
+    </g>
 </svg>
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/dictionary/aws.dictionary.ts b/services/self-service/src/main/resources/webapp/src/dictionary/aws.dictionary.ts
index f989415..78fb9a5 100644
--- a/services/self-service/src/main/resources/webapp/src/dictionary/aws.dictionary.ts
+++ b/services/self-service/src/main/resources/webapp/src/dictionary/aws.dictionary.ts
@@ -41,9 +41,9 @@
         'service': 'product',
         'service_filter_key': 'product',
         'type': 'resource_type',
-        'resourceType': 'dlab_resource_type',
+        'resourceType': 'data_lab_resource_type',
         'instance_size': 'shape',
-        'dlabId': 'dlab_id'
+        'datalab_id': 'datalab_id'
     },
     'service': 'Service',
     'type': 'Type',
@@ -55,7 +55,7 @@
     'datalake_name': '',
     'datalake_user_directory_name': '',
     'datalake_shared_directory_name': '',
-    'docker.dlab-dataengine-service': {
+    'docker.datalab-dataengine-service': {
         'total_instance_number_min': 'min_emr_instance_count',
         'total_instance_number_max': 'max_emr_instance_count',
         'min_emr_spot_instance_bid_pct': 'min_emr_spot_instance_bid_pct',
@@ -64,7 +64,7 @@
         'slave_node_shape': 'slave_node_shape',
         'total_instance_number': 'total_instance_number',
     },
-    'docker.dlab-dataengine': {
+    'docker.datalab-dataengine': {
         'total_instance_number_min': 'min_spark_instance_count',
         'total_instance_number_max': 'max_spark_instance_count',
         'data_engine_master_instance_size': 'Node shape',
diff --git a/services/self-service/src/main/resources/webapp/src/dictionary/azure.dictionary.ts b/services/self-service/src/main/resources/webapp/src/dictionary/azure.dictionary.ts
index b7d9abc..ddce787 100644
--- a/services/self-service/src/main/resources/webapp/src/dictionary/azure.dictionary.ts
+++ b/services/self-service/src/main/resources/webapp/src/dictionary/azure.dictionary.ts
@@ -44,7 +44,7 @@
         'type': '',
         'resourceType': 'resource_type',
         'instance_size': 'size',
-        'dlabId': 'dlabId'
+        'datalab_id': 'datalab_id'
     },
     'service': 'Category',
     'type': '',
@@ -56,7 +56,7 @@
     'datalake_name': 'datalake_name',
     'datalake_user_directory_name': 'datalake_user_directory_name',
     'datalake_shared_directory_name': 'datalake_shared_directory_name',
-    'docker.dlab-dataengine-service': {
+    'docker.datalab-dataengine-service': {
         'total_instance_number_min': 'min_emr_instance_count',
         'total_instance_number_max': 'max_emr_instance_count',
         'min_emr_spot_instance_bid_pct': 'min_emr_spot_instance_bid_pct',
@@ -65,7 +65,7 @@
         'slave_node_shape': 'slave_node_shape',
         'total_instance_number': 'total_instance_number',
     },
-    'docker.dlab-dataengine': {
+    'docker.datalab-dataengine': {
         'total_instance_number_min': 'min_spark_instance_count',
         'total_instance_number_max': 'max_spark_instance_count',
         'data_engine_master_instance_size': 'Node size',
diff --git a/services/self-service/src/main/resources/webapp/src/dictionary/gcp.dictionary.ts b/services/self-service/src/main/resources/webapp/src/dictionary/gcp.dictionary.ts
index d92b7ff..a71804c 100644
--- a/services/self-service/src/main/resources/webapp/src/dictionary/gcp.dictionary.ts
+++ b/services/self-service/src/main/resources/webapp/src/dictionary/gcp.dictionary.ts
@@ -40,10 +40,10 @@
         'dateTo': 'to',
         'service': 'product',
         'service_filter_key': 'product',
-        'type': 'dlab_resource_type',
-        'resourceType': 'dlab_resource_type',
+        'type': 'data_lab_resource_type',
+        'resourceType': 'data_lab_resource_type',
         'instance_size': 'shapes',
-        'dlabId': 'dlab_id'
+        'datalab_id': 'datalab_id'
     },
     'service': 'Product',
     'type': 'Resource',
@@ -55,7 +55,7 @@
     'datalake_name': '',
     'datalake_user_directory_name': '',
     'datalake_shared_directory_name': '',
-    'docker.dlab-dataengine-service': {
+    'docker.datalab-dataengine-service': {
         'total_instance_number_min': 'min_instance_count',
         'total_instance_number_max': 'max_instance_count',
         'min_emr_spot_instance_bid_pct': 'min_emr_spot_instance_bid_pct',
@@ -67,7 +67,7 @@
         'total_instance_number': 'total_master_instance_number',
         'total_slave_instance_number': 'total_slave_instance_number',
     },
-    'docker.dlab-dataengine': {
+    'docker.datalab-dataengine': {
         'total_instance_number_min': 'min_spark_instance_count',
         'total_instance_number_max': 'max_spark_instance_count',
         'data_engine_master_instance_size': 'Machine type',
diff --git a/services/self-service/src/main/resources/webapp/src/dictionary/global.dictionary.ts b/services/self-service/src/main/resources/webapp/src/dictionary/global.dictionary.ts
index 26fe456..a6b160d 100644
--- a/services/self-service/src/main/resources/webapp/src/dictionary/global.dictionary.ts
+++ b/services/self-service/src/main/resources/webapp/src/dictionary/global.dictionary.ts
@@ -43,7 +43,7 @@
     public shapes: Array<string>,
     public date_start: string,
     public date_end: string,
-    public dlab_id: string,
+    public datalab_id: string,
     public projects: Array<string>
   ) { }
 
@@ -55,7 +55,7 @@
     this.shapes = [];
     this.date_start = '';
     this.date_end = '';
-    this.dlab_id = '';
+    this.datalab_id = '';
     this.projects = [];
   }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/favicon.ico b/services/self-service/src/main/resources/webapp/src/favicon.ico
index 2bb416d..3a72b5a 100644
--- a/services/self-service/src/main/resources/webapp/src/favicon.ico
+++ b/services/self-service/src/main/resources/webapp/src/favicon.ico
Binary files differ
diff --git a/services/self-service/src/main/resources/webapp/src/index.html b/services/self-service/src/main/resources/webapp/src/index.html
index 849c5f1..d7e4763 100644
--- a/services/self-service/src/main/resources/webapp/src/index.html
+++ b/services/self-service/src/main/resources/webapp/src/index.html
@@ -23,7 +23,7 @@
 
 <head>
   <meta charset="utf-8">
-  <title>DLab</title>
+  <title>DataLab</title>
   <base href="/">
 
   <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -34,6 +34,7 @@
     body,
     html {
       height: 100%;
+      margin: 0;
     }
 
     .app-loading {
@@ -46,16 +47,14 @@
     }
 
     .app-loading .spinner {
-      height: 200px;
-      width: 200px;
+      height: 270px;
+      width: 270px;
       animation: rotate 2s linear infinite;
       transform-origin: center center;
       position: absolute;
-      top: 0;
-      bottom: 0;
-      left: 0;
-      right: 0;
-      margin: auto;
+      top: calc(50% - 135px);
+      left: calc(50% - 135px);
+      margin: 0;
     }
 
     .app-loading .spinner .path {
@@ -96,14 +95,19 @@
   <app-root>
     <div class="app-loading">
       <div class="logo">
-        <svg version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 140.5 47.1" width="100px" height="100px"
-          style="enable-background:new 0 0 140.5 47.1;" xml:space="preserve">
-          <path fill="#35AFD5"
-            d="M0.9,46C0.3,45.4,0,44.6,0,43.7V3.1c0-0.8,0.3-1.7,0.9-2.2C1.5,0.3,2.3,0,3.1,0H14c4.2-0.1,8.3,1,12,3 c3.5,1.9,6.3,4.8,8.2,8.3c2,3.7,3,7.9,3,12.1c0.1,4.2-0.9,8.4-2.9,12.1c-1.9,3.5-4.8,6.4-8.3,8.3c-3.7,2-7.8,3.1-12.1,3H3.1 C2.3,46.9,1.5,46.6,0.9,46z M14,41.3c3.1,0.1,6.2-0.7,8.9-2.3c2.6-1.5,4.7-3.7,6.1-6.4c1.5-2.9,2.2-6,2.2-9.3 c0.1-3.2-0.7-6.4-2.2-9.2c-1.4-2.7-3.5-4.9-6.1-6.4c-2.7-1.5-5.8-2.3-8.9-2.3H6.2v35.8H14z M41.8,46.2C41.3,45.6,41,44.8,41,44V3.4 c0-0.8,0.3-1.6,0.9-2.2c0.6-0.6,1.3-0.9,2.1-0.9c1.7,0,3.1,1.3,3.1,3c0,0,0,0.1,0,0.1v37.5h21.8c1.7,0,3.1,1.4,3.1,3.1 c0,1.7-1.4,3.1-3.1,3.1c0,0,0,0,0,0H44C43.2,47.1,42.4,46.8,41.8,46.2z M96.2,16c2.5,1.4,4.5,3.5,5.9,6c1.5,2.6,2.2,5.5,2.2,8.5 v13.4c0,1.7-1.4,3.1-3.1,3.1c-1.7,0-3.1-1.4-3.1-3.1v-2.2c-4.8,5.7-13,7.1-19.4,3.3c-2.4-1.5-4.3-3.5-5.5-6c-1.4-2.6-2-5.5-2-8.5 c0-3,0.7-5.9,2.1-8.4c1.4-2.5,3.5-4.6,6-6c2.6-1.5,5.5-2.2,8.4-2.2C90.7,13.8,93.6,14.5,96.2,16z M93.2,40.2c1.6-1,2.9-2.3,3.8-4 c0.9-1.8,1.4-3.7,1.4-5.7c0-2-0.5-4-1.4-5.8c-2.8-5.1-9.2-7-14.4-4.2c-0.1,0.1-0.2,0.1-0.3,0.2c-1.6,1-2.9,2.3-3.8,4 c-1,1.8-1.4,3.8-1.4,5.8c0,2,0.5,4,1.4,5.7c0.9,1.7,2.2,3,3.8,4C85.7,42.2,89.8,42.2,93.2,40.2L93.2,40.2z M132.9,16 c2.4,1.5,4.3,3.5,5.5,6c1.4,2.6,2,5.5,2,8.5c0,3-0.7,5.9-2.2,8.5c-1.4,2.5-3.5,4.6-6,6c-2.6,1.5-5.5,2.2-8.4,2.2 c-5.9,0.1-11.4-3.1-14.3-8.2c-1.5-2.6-2.2-5.5-2.2-8.5V3.1c0-0.8,0.3-1.6,0.9-2.2c1.3-1.1,3.2-1.1,4.4,0c0.6,0.6,0.9,1.4,0.8,2.2 v16.2C118.3,13.5,126.5,12.1,132.9,16z M129.3,40.3c1.6-1,2.9-2.4,3.8-4c1-1.8,1.4-3.8,1.4-5.8c0-2-0.5-4-1.4-5.7 c-0.9-1.7-2.2-3-3.8-4c-4.9-3-11.4-1.4-14.4,3.5c-0.1,0.2-0.2,0.3-0.3,0.5c-0.9,1.8-1.4,3.7-1.4,5.7c0,2,0.4,4,1.4,5.8 c2.8,5.1,9.2,7,14.4,4.2C129.1,40.4,129.2,40.3,129.3,40.3z M41,0.1h6.2v5.3H41V0.1z M0,0h6.1v5.3H0V0z M0,41.5h6.1v5.3H0V41.5z  M65.9,40.9H72v6.2h-6.1V40.9z M41,41.9h3.5v5.2H41V41.9z M98.2,41.3h6.1v5.6h-6.1V41.3z M107.4,0h6.1v5.4h-6.1V0z" />
+        <svg width="175px" height="100px" viewBox="0 0 309 152" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+          <title>Group</title>
+          <g id="Page-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+            <g id="Artboard-Copy" transform="translate(-100.000000, -6.000000)" fill="#35AFD5" fill-rule="nonzero">
+              <g id="Group" transform="translate(100.000000, 6.000000)">
+                <path d="M48,0 L48,50.304 L48.040916,55.668891 L47.950033,55.677562 L46.6386939,55.8175213 L45.9255692,55.900871 L45.8143969,55.915542 C23.9652352,58.951769 7.5,77.7148504 7.5,99.9895207 C7.5,124.566192 27.4233286,144.489521 52,144.489521 C63.7945578,144.489521 74.850976,139.884216 83.1068414,131.811186 L83.5172913,131.404651 L88.4750135,136.34641 C78.8766784,145.975749 65.8707068,151.489521 52,151.489521 C23.5573354,151.489521 0.5,128.432185 0.5,99.9895207 C0.5,75.5349665 17.6438798,54.7411444 40.9999076,49.6668368 L41,7 L32,7 L32,0 L48,0 Z M165.725133,87 C180.659525,87 185.571785,99.997962 185.668537,106.310769 L185.67,106.5 L185.67,125.401152 L179.21943,125.401152 L179.21943,120.31094 C176.401939,123.454894 171.804981,126 165.725133,126 C155.27076,126 146.67,117.466411 146.67,106.537428 C146.67,95.6084453 155.27076,87 165.725133,87 Z M100.725133,87 C115.659525,87 120.571785,99.997962 120.668537,106.310769 L120.67,106.5 L120.67,125.401152 L114.21943,125.401152 L114.21943,120.31094 C111.401939,123.454894 106.804981,126 100.725133,126 C90.2707605,126 81.67,117.466411 81.67,106.537428 C81.67,95.6084453 90.2707605,87 100.725133,87 Z M276.194715,74 L276.194715,92.030303 C279.160494,89.012987 283.683308,86.6580087 289.614867,86.6580087 C300.06924,86.6580087 308.67,95.1212121 308.67,105.865801 C308.67,116.61039 300.06924,125 289.614867,125 C281.830928,125 269.921189,119.162503 269.673914,106.275116 L269.67,105.865801 L269.67,74 L276.194715,74 Z M200.895734,74 L200.895734,118.373723 L226.67,118.373723 L226.67,125 L193.67,125 L193.67,74 L200.895734,74 Z M245.725133,86 C260.659525,86 265.571785,98.997962 265.668537,105.310769 L265.67,105.5 L265.67,124.401152 L259.21943,124.401152 L259.21943,119.31094 C256.401939,122.454894 251.804981,125 245.725133,125 C235.27076,125 226.67,116.466411 226.67,105.537428 C226.67,94.6084453 235.27076,86 245.725133,86 Z M52.76,74.31 C67.412,74.31 78.438,85.336 78.438,99.544 C78.438,113.68318 67.6314174,124.776209 53.1984648,124.996656 L52.76,125 L35,125 L35,74.31 L52.76,74.31 Z M135.658,77 L135.658,87.286 L145.574,87.286 L145.574,93.058 L135.658,93.058 L135.658,112.668 C135.658,117.45432 138.429714,118.900369 141.814049,118.956296 L142.022,118.958 L145.574,118.958 L145.574,124.73 L141.948,124.73 C134.582319,124.73 129.372756,121.136469 129.223301,113.028631 L129.22,112.668 L129.22,93.058 L123.67,93.058 L123.67,87.286 L129.22,87.286 L129.22,77 L135.658,77 Z M166.095856,93.1381958 C158.681407,93.1381958 153.046426,99.0518234 153.046426,106.537428 C153.046426,114.023033 158.681407,119.93666 166.095856,119.93666 C173.658593,119.93666 179.367719,114.097889 179.367719,106.537428 C179.367719,99.0518234 173.584449,93.1381958 166.095856,93.1381958 Z M101.095856,93.1381958 C93.6814068,93.1381958 88.0464259,99.0518234 88.0464259,106.537428 C88.0464259,114.023033 93.6814068,119.93666 101.095856,119.93666 C108.658593,119.93666 114.367719,114.097889 114.367719,106.537428 C114.367719,99.0518234 108.584449,93.1381958 101.095856,93.1381958 Z M289.244144,92.6926407 C281.755551,92.6926407 275.972281,98.5064935 275.972281,105.865801 C275.972281,113.298701 281.681407,119.038961 289.244144,119.038961 C296.658593,119.038961 302.293574,113.225108 302.293574,105.865801 C302.293574,98.5064935 296.658593,92.6926407 289.244144,92.6926407 Z M246.095856,92.1381958 C238.681407,92.1381958 233.046426,98.0518234 233.046426,105.537428 C233.046426,113.023033 238.681407,118.93666 246.095856,118.93666 C253.658593,118.93666 259.367719,113.097889 259.367719,105.537428 C259.367719,98.0518234 253.584449,92.1381958 246.095856,92.1381958 Z M52.464,80.896 L42.178,80.896 L42.178,118.414 L52.316,118.414 C63.416,118.414 71.26,110.2 71.26,99.692 C71.26,89.036 63.194,80.896 52.464,80.896 Z M72,0 L72,7 L62.9994923,7 L63.0003609,49.6793321 C72.3934241,51.7252087 80.9885914,56.3662817 87.8723853,63.0520566 L88.3188454,63.4909316 L83.3817065,68.4532556 C76.4855783,61.5921271 67.5443496,57.1475703 57.8192825,55.8771804 L57.1166971,55.791461 L56.0381427,55.6853811 L55.9874923,55.6803995 L55.9994923,50.98 L56,0 L72,0 Z" id="Combined-Shape"></path>
+              </g>
+            </g>
+          </g>
         </svg>
       </div>
       <svg class="spinner" viewBox="25 25 50 50">
-        <circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="1" stroke-miterlimit="10" />
+        <circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="0.6" stroke-miterlimit="10" />
       </svg>
     </div>
   </app-root>
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/.gitkeep b/services/self-service/src/test/java/com/epam/datalab/backendapi/.gitkeep
similarity index 100%
rename from services/self-service/src/test/java/com/epam/dlab/backendapi/.gitkeep
rename to services/self-service/src/test/java/com/epam/datalab/backendapi/.gitkeep
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/domain/ExploratoryLibListTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/domain/ExploratoryLibListTest.java
new file mode 100644
index 0000000..fe15cde
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/domain/ExploratoryLibListTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.datalab.backendapi.domain;
+
+import com.epam.datalab.backendapi.resources.dto.LibraryAutoCompleteDTO;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+
+public class ExploratoryLibListTest {
+
+	@Test
+	public void getLibs() {
+		String content =
+				"{" +
+						"\"os_pkg\": {\"htop\": \"2.0.1-1ubuntu1\", \"python-mysqldb\": \"1.3.7-1build2\"}," +
+						"\"pip2\": {\"requests\": \"N/A\", \"configparser\": \"N/A\"}," +
+						"\"pip3\": {\"configparser\": \"N/A\"}," +
+						"\"r_pkg\": {\"rmarkdown\": \"1.5\"}" +
+						"}";
+
+		ExploratoryLibList libs = new ExploratoryLibList("imageName", content);
+
+		assertEquals("imageName", libs.getGroup());
+		assertFalse(libs.isExpired());
+		assertFalse(libs.isUpdateNeeded());
+		assertFalse(libs.isUpdating());
+
+		List<String> groups = libs.getGroupList();
+		assertEquals(4, groups.size());
+		assertEquals("os_pkg", groups.get(0));
+		assertEquals("r_pkg", groups.get(3));
+
+		Map<String, String> map = libs.getLibs("os_pkg");
+		assertEquals(2, map.size());
+		assertEquals("2.0.1-1ubuntu1", map.get("htop"));
+		assertEquals("1.3.7-1build2", map.get("python-mysqldb"));
+
+		final LibraryAutoCompleteDTO dtoList = libs.getLibs("os_pkg", "py");
+		assertEquals(1, dtoList.getLibraries().size());
+		assertEquals("1.3.7-1build2", dtoList.getLibraries().get(0).getVersion());
+
+		libs.setUpdating();
+		assertTrue(libs.isUpdating());
+	}
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ApplicationSettingResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ApplicationSettingResourceTest.java
new file mode 100644
index 0000000..949741a
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ApplicationSettingResourceTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+
+import com.epam.datalab.backendapi.service.ApplicationSettingService;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class ApplicationSettingResourceTest extends TestBase {
+
+    private ApplicationSettingService applicationSettingService = mock(ApplicationSettingService.class);
+
+    @Rule
+    public final ResourceTestRule resources =
+            getResourceTestRuleInstance(new ApplicationSettingResource(applicationSettingService));
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+
+    @Test
+    public void setMaxBudget() {
+        final Response response = resources.getJerseyTest()
+                .target("/settings/budget/12")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .put(Entity.entity("dummy", MediaType.TEXT_PLAIN));
+
+        assertEquals(HttpStatus.SC_NO_CONTENT, response.getStatus());
+
+        verify(applicationSettingService).setMaxBudget(12L);
+        verifyNoMoreInteractions(applicationSettingService);
+    }
+
+    @Test
+    public void removeMaxBudget() {
+        final Response response = resources.getJerseyTest()
+                .target("/settings/budget")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .delete();
+
+        assertEquals(HttpStatus.SC_NO_CONTENT, response.getStatus());
+
+        verify(applicationSettingService).removeMaxBudget();
+        verifyNoMoreInteractions(applicationSettingService);
+    }
+
+    @Test
+    public void getSettings() {
+
+        when(applicationSettingService.getSettings()).thenReturn(Collections.singletonMap("key", "value"));
+        final Response response = resources.getJerseyTest()
+                .target("/settings")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+        final Map map = response.readEntity(Map.class);
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getMediaType());
+        assertEquals(1, map.size());
+        assertEquals("value", map.get("key"));
+
+        verify(applicationSettingService).getSettings();
+        verifyNoMoreInteractions(applicationSettingService);
+
+
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/AuditResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/AuditResourceTest.java
new file mode 100644
index 0000000..f7fc60f
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/AuditResourceTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.backendapi.domain.AuditCreateDTO;
+import com.epam.datalab.backendapi.domain.AuditResourceTypeEnum;
+import com.epam.datalab.backendapi.service.AuditService;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+public class AuditResourceTest extends TestBase {
+
+    private final static String USER = "testuser";
+    private final static String INFO = "testInfo";
+    private final static String RESOURCE = "testResource";
+
+    private final AuditService auditService = mock(AuditService.class);
+
+    @Rule
+    public final ResourceTestRule resources = getResourceTestRuleInstance(new AuditResource(auditService));
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Test
+    public void saveAudit() {
+        final Response response = resources.getJerseyTest()
+                .target("/audit")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(prepareAuditCreateDTO()));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        verify(auditService).save(eq(USER), refEq(prepareAuditCreateDTO()));
+        verifyNoMoreInteractions(auditService);
+    }
+
+    @Test
+    public void getAudit() {
+        final Response response = resources.getJerseyTest()
+                .target("/audit")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+    }
+
+    private AuditCreateDTO prepareAuditCreateDTO() {
+        return new AuditCreateDTO(RESOURCE, INFO, AuditResourceTypeEnum.COMPUTE);
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/BackupResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/BackupResourceTest.java
new file mode 100644
index 0000000..0e14032
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/BackupResourceTest.java
@@ -0,0 +1,228 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.resources.dto.BackupFormDTO;
+import com.epam.datalab.backendapi.resources.dto.BackupInfoRecord;
+import com.epam.datalab.backendapi.service.BackupService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.dto.backup.EnvBackupDTO;
+import com.epam.datalab.dto.backup.EnvBackupStatus;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class BackupResourceTest extends TestBase {
+
+    private final Date TIMESTAMP = new Date();
+    private BackupService backupService = mock(BackupService.class);
+    private RequestId requestId = mock(RequestId.class);
+    private RequestBuilder requestBuilder = mock(RequestBuilder.class);
+
+    @Rule
+    public final ResourceTestRule resources =
+            getResourceTestRuleInstance(new BackupResource(backupService, requestBuilder, requestId));
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Test
+    public void getBackup() {
+        when(backupService.getBackup(anyString(), anyString())).thenReturn(getBackupInfo());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/backup/1")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getBackupInfo(), response.readEntity(BackupInfoRecord.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(backupService).getBackup(USER.toLowerCase(), "1");
+        verifyNoMoreInteractions(backupService);
+        verifyZeroInteractions(requestId, requestBuilder);
+    }
+
+    @Test
+    public void getBackupWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(backupService.getBackup(anyString(), anyString())).thenReturn(getBackupInfo());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/backup/1")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verifyZeroInteractions(backupService, requestId, requestBuilder);
+    }
+
+    @Test
+    public void getBackupWithNotFoundException() {
+        when(backupService.getBackup(anyString(), anyString())).thenThrow(new ResourceNotFoundException("Backup not " +
+                "found"));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/backup/1")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_NOT_FOUND, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(backupService).getBackup(USER.toLowerCase(), "1");
+        verifyNoMoreInteractions(backupService);
+        verifyZeroInteractions(requestId, requestBuilder);
+    }
+
+    @Test
+    public void getBackups() {
+        when(backupService.getBackups(anyString())).thenReturn(Collections.singletonList(getBackupInfo()));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/backup")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(Collections.singletonList(getBackupInfo()),
+                response.readEntity(new GenericType<List<BackupInfoRecord>>() {
+                }));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(backupService).getBackups(USER.toLowerCase());
+        verifyNoMoreInteractions(backupService);
+        verifyZeroInteractions(requestId, requestBuilder);
+    }
+
+    @Test
+    public void getBackupsWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(backupService.getBackups(anyString())).thenReturn(Collections.singletonList(getBackupInfo()));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/backup")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verifyZeroInteractions(backupService, requestId, requestBuilder);
+    }
+
+    @Test
+    public void createBackup() {
+        when(requestBuilder.newBackupCreate(any(BackupFormDTO.class), anyString())).thenReturn(getEnvBackupDto());
+        when(backupService.createBackup(any(EnvBackupDTO.class), any(UserInfo.class))).thenReturn("someUuid");
+        when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
+
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/backup")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getBackupFormDto()));
+
+        assertEquals(HttpStatus.SC_ACCEPTED, response.getStatus());
+        assertEquals(MediaType.TEXT_PLAIN, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(requestBuilder).newBackupCreate(eq(getBackupFormDto()), anyString());
+        verify(backupService).createBackup(getEnvBackupDto(), getUserInfo());
+        verify(requestId).put(USER.toLowerCase(), "someUuid");
+        verifyNoMoreInteractions(requestBuilder, backupService, requestId);
+    }
+
+    @Test
+    public void createBackupWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(requestBuilder.newBackupCreate(any(BackupFormDTO.class), anyString())).thenReturn(getEnvBackupDto());
+        when(backupService.createBackup(any(EnvBackupDTO.class), any(UserInfo.class))).thenReturn("someUuid");
+        when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
+
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/backup")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getBackupFormDto()));
+
+        assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verifyZeroInteractions(requestBuilder, backupService, requestId);
+    }
+
+    private BackupInfoRecord getBackupInfo() {
+        final List<String> configFiles = Arrays.asList("ss.yml", "sec.yml");
+        final List<String> keys = Collections.singletonList("key.pub");
+        final List<String> cert = Collections.singletonList("cert");
+        final List<String> jars = Collections.singletonList("ss.jar");
+        return new BackupInfoRecord(configFiles, keys, cert, jars, false, true, "file.backup",
+                EnvBackupStatus.CREATED, null, TIMESTAMP);
+    }
+
+    private BackupFormDTO getBackupFormDto() {
+        return new BackupFormDTO(Arrays.asList("ss.yml", "sec.yml"), Collections.singletonList("key.pub"),
+                Collections.singletonList("cert"), Collections.singletonList("ss.jar"), false, true);
+    }
+
+    private EnvBackupDTO getEnvBackupDto() {
+        return EnvBackupDTO.builder()
+                .configFiles(Arrays.asList("ss.yml", "sec.yml"))
+                .keys(Collections.singletonList("key.pub"))
+                .certificates(Collections.singletonList("cert"))
+                .jars(Collections.singletonList("ss.jar"))
+                .databaseBackup(false)
+                .logsBackup(true)
+                .backupFile("file.backup")
+                .id("someId")
+                .build();
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/EnvironmentResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/EnvironmentResourceTest.java
new file mode 100644
index 0000000..d5abaa2
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/EnvironmentResourceTest.java
@@ -0,0 +1,291 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.EnvironmentService;
+import com.epam.datalab.exceptions.ResourceConflictException;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class EnvironmentResourceTest extends TestBase {
+
+    private EnvironmentService environmentService = mock(EnvironmentService.class);
+
+    @Rule
+    public final ResourceTestRule resources = getResourceTestRuleInstance(new EnvironmentResource(environmentService));
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Test
+    public void getAllEnv() {
+        UserInfo userInfo = getUserInfo();
+        when(environmentService.getAllEnv(userInfo)).thenReturn(Collections.emptyList());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/all")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(environmentService).getAllEnv(eq(userInfo));
+        verifyNoMoreInteractions(environmentService);
+    }
+
+    @Test
+    public void getAllEnvWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(environmentService.getAllEnv(getUserInfo())).thenReturn(Collections.emptyList());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/all")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verifyZeroInteractions(environmentService);
+    }
+
+    @Test
+    public void stopNotebook() {
+        doNothing().when(environmentService).stopExploratory(any(UserInfo.class), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/stop/projectName/explName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.text(USER));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(environmentService).stopExploratory(new UserInfo(USER, TOKEN), USER, "projectName", "explName");
+        verifyNoMoreInteractions(environmentService);
+    }
+
+    @Test
+    public void stopNotebookWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        doNothing().when(environmentService).stopExploratory(any(UserInfo.class), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/stop/projectName/explName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.text(USER));
+
+        assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verifyZeroInteractions(environmentService);
+    }
+
+    @Test
+    public void stopNotebookWithResourceConflictException() {
+        doThrow(new ResourceConflictException("Can not stop notebook because its status is CREATING or STARTING"))
+                .when(environmentService).stopExploratory(any(UserInfo.class), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/stop/projectName/explName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.text(USER));
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(environmentService).stopExploratory(new UserInfo(USER, TOKEN), USER, "projectName", "explName");
+        verifyNoMoreInteractions(environmentService);
+    }
+
+    @Test
+    public void stopCluster() {
+        doNothing().when(environmentService).stopComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/stop/projectName/explName/compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.text(USER));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(environmentService).stopComputational(new UserInfo(USER, TOKEN), USER, "projectName", "explName", "compName");
+        verifyNoMoreInteractions(environmentService);
+    }
+
+    @Test
+    public void stopClusterWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        doNothing().when(environmentService).stopComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/stop/projectName/explName/compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.text(USER));
+
+        assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verifyZeroInteractions(environmentService);
+    }
+
+    @Test
+    public void stopClusterWithResourceConflictException() {
+        doThrow(new ResourceConflictException("Can not stop cluster because its status is CREATING or STARTING"))
+                .when(environmentService).stopComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/stop/projectName/explName/compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.text(USER));
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(environmentService).stopComputational(new UserInfo(USER, TOKEN), USER, "projectName", "explName", "compName");
+        verifyNoMoreInteractions(environmentService);
+    }
+
+    @Test
+    public void terminateNotebook() {
+        doNothing().when(environmentService).terminateExploratory(any(UserInfo.class), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/terminate/projectName/explName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.text(USER));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(environmentService).terminateExploratory(new UserInfo(USER, TOKEN), USER, "projectName", "explName");
+        verifyNoMoreInteractions(environmentService);
+    }
+
+    @Test
+    public void terminateNotebookWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        doNothing().when(environmentService).terminateExploratory(any(UserInfo.class), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/terminate/projectName/explName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.text(USER));
+
+        assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verifyZeroInteractions(environmentService);
+    }
+
+    @Test
+    public void terminateNotebookWithResourceConflictException() {
+        doThrow(new ResourceConflictException("Can not terminate notebook because its status is CREATING or STARTING"))
+                .when(environmentService).terminateExploratory(any(UserInfo.class), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/terminate/projectName/explName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.text(USER));
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(environmentService).terminateExploratory(new UserInfo(USER, TOKEN), USER, "projectName", "explName");
+        verifyNoMoreInteractions(environmentService);
+    }
+
+    @Test
+    public void terminateCluster() {
+        doNothing().when(environmentService).terminateComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/terminate/projectName/explName/compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.text(USER));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(environmentService).terminateComputational(new UserInfo(USER, TOKEN), USER, "projectName", "explName", "compName");
+        verifyNoMoreInteractions(environmentService);
+    }
+
+    @Test
+    public void terminateClusterWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        doNothing().when(environmentService).terminateComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/terminate/projectName/explName/compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.text(USER));
+
+        assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verifyZeroInteractions(environmentService);
+    }
+
+    @Test
+    public void terminateClusterWithResourceConflictException() {
+        doThrow(new ResourceConflictException("Can not terminate cluster because its status is CREATING or STARTING"))
+                .when(environmentService).terminateComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/environment/terminate/projectName/explName/compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.text(USER));
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(environmentService).terminateComputational(new UserInfo(USER, TOKEN), USER, "projectName", "explName", "compName");
+        verifyNoMoreInteractions(environmentService);
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ExploratoryResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ExploratoryResourceTest.java
new file mode 100644
index 0000000..0f2a8f0
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ExploratoryResourceTest.java
@@ -0,0 +1,325 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.ExploratoryActionFormDTO;
+import com.epam.datalab.backendapi.resources.dto.ExploratoryCreateFormDTO;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.model.exploratory.Exploratory;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+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.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class ExploratoryResourceTest extends TestBase {
+
+    private ExploratoryService exploratoryService = mock(ExploratoryService.class);
+
+    @Rule
+    public final ResourceTestRule resources = getResourceTestRuleInstance(new ExploratoryResource(exploratoryService));
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Test
+    public void create() {
+        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 DatalabException("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()));
+
+        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", "someName");
+        verifyNoMoreInteractions(exploratoryService);
+    }
+
+    @Test
+    public void start() {
+        ExploratoryActionFormDTO exploratoryDTO = getExploratoryActionFormDTO();
+        when(exploratoryService.start(any(UserInfo.class), anyString(), anyString(), anyString())).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));
+
+        verify(exploratoryService).start(getUserInfo(), exploratoryDTO.getNotebookInstanceName(), exploratoryDTO.getProjectName(), null);
+
+        verifyZeroInteractions(exploratoryService);
+    }
+
+    @Test
+    public void startUnprocessableEntity() {
+        when(exploratoryService.start(any(UserInfo.class), anyString(), 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_UNPROCESSABLE_ENTITY, 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(), anyString())).thenReturn("someUuid");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/project/someName/stop")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .delete();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals("someUuid", response.readEntity(String.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        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(), anyString(), anyString())).thenReturn("someUuid");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/project/someName/stop")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .delete();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals("someUuid", response.readEntity(String.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(exploratoryService).stop(getUserInfo(), getUserInfo().getName(), "project", "someName", null);
+        verifyNoMoreInteractions(exploratoryService);
+    }
+
+    @Test
+    public void stopWithException() {
+        doThrow(new DatalabException("Could not stop exploratory environment"))
+                .when(exploratoryService).stop(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/project/someName/stop")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .delete();
+
+        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).stop(getUserInfo(), getUserInfo().getName(), "project", "someName", null);
+        verifyNoMoreInteractions(exploratoryService);
+    }
+
+    @Test
+    public void terminate() {
+        when(exploratoryService.terminate(any(UserInfo.class), anyString(), anyString(), anyString(), anyString())).thenReturn("someUuid");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/project/someName/terminate")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .delete();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals("someUuid", response.readEntity(String.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        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(), anyString(), anyString())).thenReturn("someUuid");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/project/someName/terminate")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .delete();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals("someUuid", response.readEntity(String.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(exploratoryService).terminate(getUserInfo(), getUserInfo().getName(), "project", "someName", null);
+        verifyNoMoreInteractions(exploratoryService);
+    }
+
+    @Test
+    public void terminateWithException() {
+        doThrow(new DatalabException("Could not terminate exploratory environment"))
+                .when(exploratoryService).terminate(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/project/someName/terminate")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .delete();
+
+        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).terminate(getUserInfo(), getUserInfo().getName(), "project", "someName", null);
+        verifyNoMoreInteractions(exploratoryService);
+    }
+
+    @Test
+    public void updateSparkConfig() {
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/someProject/someName/reconfigure")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .put(Entity.json(Collections.singletonList(new ClusterConfig())));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+
+        verify(exploratoryService).updateClusterConfig(refEq(getUserInfo()), eq("someProject"),
+                eq("someName"), eq(Collections.singletonList(new ClusterConfig())));
+        verifyNoMoreInteractions(exploratoryService);
+    }
+
+    @Test
+    public void getSparkConfig() {
+        final ClusterConfig config = new ClusterConfig();
+        config.setClassification("test");
+        when(exploratoryService.getClusterConfig(any(UserInfo.class), anyString(), anyString())).thenReturn(Collections.singletonList(config));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/someProject/someName/cluster/config")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        final List<ClusterConfig> clusterConfigs = response.readEntity(new GenericType<List<ClusterConfig>>() {
+        });
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(1, clusterConfigs.size());
+        assertEquals("test", clusterConfigs.get(0).getClassification());
+
+        verify(exploratoryService).getClusterConfig(refEq(getUserInfo()), eq("someProject"), eq("someName"));
+        verifyNoMoreInteractions(exploratoryService);
+    }
+
+    private ExploratoryCreateFormDTO getExploratoryCreateFormDTO() {
+        ExploratoryCreateFormDTO ecfDto = new ExploratoryCreateFormDTO();
+        ecfDto.setImage("someImage");
+        ecfDto.setTemplateName("someTemplateName");
+        ecfDto.setName("someName");
+        ecfDto.setShape("someShape");
+        ecfDto.setVersion("someVersion");
+        ecfDto.setImageName("someImageName");
+        ecfDto.setProject("project");
+        ecfDto.setEndpoint("endpoint");
+        return ecfDto;
+    }
+
+    private ExploratoryActionFormDTO getEmptyExploratoryActionFormDTO() {
+        return new ExploratoryActionFormDTO();
+    }
+
+    private ExploratoryActionFormDTO getExploratoryActionFormDTO() {
+        return new ExploratoryActionFormDTO("notebook_instance_name", "project_name");
+    }
+
+    private Exploratory getExploratory(@Valid @NotNull ExploratoryCreateFormDTO formDTO) {
+        return Exploratory.builder()
+                .name(formDTO.getName())
+                .dockerImage(formDTO.getImage())
+                .imageName(formDTO.getImageName())
+                .templateName(formDTO.getTemplateName())
+                .version(formDTO.getVersion())
+                .shape(formDTO.getShape())
+                .endpoint(formDTO.getEndpoint())
+                .project(formDTO.getProject()).build();
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/GitCredsResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/GitCredsResourceTest.java
new file mode 100644
index 0000000..ec0e67d
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/GitCredsResourceTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.GitCredentialService;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCreds;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class GitCredsResourceTest extends TestBase {
+
+	private GitCredentialService gitCredentialService = mock(GitCredentialService.class);
+
+	@Rule
+	public final ResourceTestRule resources = getResourceTestRuleInstance(new GitCredsResource(gitCredentialService));
+
+	@Before
+	public void setup() throws AuthenticationException {
+		authSetup();
+	}
+
+	@Test
+	public void updateGitCreds() {
+		doNothing().when(gitCredentialService).updateGitCredentials(any(UserInfo.class),
+				any(ExploratoryGitCredsDTO.class));
+		final Response response = resources.getJerseyTest()
+				.target("/user/git_creds")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.put(Entity.json(getExploratoryGitCredsDTO()));
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(gitCredentialService)
+				.updateGitCredentials(refEq(getUserInfo()), refEq(getExploratoryGitCredsDTO(), "self"));
+		verifyNoMoreInteractions(gitCredentialService);
+	}
+
+	@Test
+	public void updateGitCredsWithFailedAuth() throws AuthenticationException {
+		authFailSetup();
+		doNothing().when(gitCredentialService).updateGitCredentials(any(UserInfo.class),
+				any(ExploratoryGitCredsDTO.class));
+		final Response response = resources.getJerseyTest()
+				.target("/user/git_creds")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.put(Entity.json(getExploratoryGitCredsDTO()));
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(gitCredentialService)
+				.updateGitCredentials(refEq(getUserInfo()), refEq(getExploratoryGitCredsDTO(), "self"));
+		verifyNoMoreInteractions(gitCredentialService);
+	}
+
+	@Test
+	public void updateGitCredsWithException() {
+		doThrow(new DatalabException("Cannot update the GIT credentials")).when(gitCredentialService)
+				.updateGitCredentials(any(UserInfo.class), any(ExploratoryGitCredsDTO.class));
+		final Response response = resources.getJerseyTest()
+				.target("/user/git_creds")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.put(Entity.json(getExploratoryGitCredsDTO()));
+
+		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(gitCredentialService).updateGitCredentials(refEq(getUserInfo()),
+				refEq(getExploratoryGitCredsDTO(), "self"));
+		verifyNoMoreInteractions(gitCredentialService);
+	}
+
+	@Test
+	public void getGitCreds() {
+		ExploratoryGitCredsDTO egcDto = getExploratoryGitCredsDTO();
+		when(gitCredentialService.getGitCredentials(anyString())).thenReturn(egcDto);
+		final Response response = resources.getJerseyTest()
+				.target("/user/git_creds")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.get();
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertEquals(egcDto.getGitCreds(), response.readEntity(ExploratoryGitCredsDTO.class).getGitCreds());
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(gitCredentialService).getGitCredentials(USER.toLowerCase());
+		verifyNoMoreInteractions(gitCredentialService);
+	}
+
+	@Test
+	public void getGitCredsWithFailedAuth() throws AuthenticationException {
+		authFailSetup();
+		ExploratoryGitCredsDTO egcDto = getExploratoryGitCredsDTO();
+		when(gitCredentialService.getGitCredentials(anyString())).thenReturn(egcDto);
+		final Response response = resources.getJerseyTest()
+				.target("/user/git_creds")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.get();
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertEquals(egcDto.getGitCreds(), response.readEntity(ExploratoryGitCredsDTO.class).getGitCreds());
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(gitCredentialService).getGitCredentials(USER.toLowerCase());
+		verifyNoMoreInteractions(gitCredentialService);
+	}
+
+	@Test
+	public void getGitCredsWithException() {
+		doThrow(new DatalabException("Cannot load GIT credentials for user"))
+				.when(gitCredentialService).getGitCredentials(anyString());
+		final Response response = resources.getJerseyTest()
+				.target("/user/git_creds")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.get();
+
+		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(gitCredentialService).getGitCredentials(USER.toLowerCase());
+		verifyNoMoreInteractions(gitCredentialService);
+	}
+
+	private ExploratoryGitCredsDTO getExploratoryGitCredsDTO() {
+		ExploratoryGitCredsDTO exploratoryGitCredsDTO = new ExploratoryGitCredsDTO();
+		final ExploratoryGitCreds exploratoryGitCreds = new ExploratoryGitCreds();
+		exploratoryGitCreds.setHostname("host");
+		exploratoryGitCredsDTO.setGitCreds(Collections.singletonList(exploratoryGitCreds));
+		return exploratoryGitCredsDTO;
+	}
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ImageExploratoryResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ImageExploratoryResourceTest.java
new file mode 100644
index 0000000..f62b1e3
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ImageExploratoryResourceTest.java
@@ -0,0 +1,282 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.resources.dto.ExploratoryImageCreateFormDTO;
+import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.backendapi.service.ImageExploratoryService;
+import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.epam.datalab.exceptions.ResourceAlreadyExistException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class ImageExploratoryResourceTest extends TestBase {
+    private final static String AUDIT_MESSAGE = "Create image: %s";
+    private static final String PROJECT = "projectName";
+    private ImageExploratoryService imageExploratoryService = mock(ImageExploratoryService.class);
+    private RequestId requestId = mock(RequestId.class);
+
+    @Rule
+    public final ResourceTestRule resources =
+            getResourceTestRuleInstance(new ImageExploratoryResource(imageExploratoryService, requestId));
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Test
+    public void createImage() {
+        when(imageExploratoryService.createImage(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString()))
+                .thenReturn("someUuid");
+        when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/image")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getExploratoryImageCreateFormDTO()));
+
+        assertEquals(HttpStatus.SC_ACCEPTED, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(imageExploratoryService).createImage(getUserInfo(), PROJECT, "someNotebookName",
+                "someImageName", "someDescription", String.format(AUDIT_MESSAGE, "someImageName"));
+        verify(requestId).put(USER.toLowerCase(), "someUuid");
+        verifyNoMoreInteractions(imageExploratoryService, requestId);
+    }
+
+    @Test
+    public void createImageWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(imageExploratoryService.createImage(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString()))
+                .thenReturn("someUuid");
+        when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/image")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getExploratoryImageCreateFormDTO()));
+
+        assertEquals(HttpStatus.SC_ACCEPTED, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(imageExploratoryService).createImage(getUserInfo(), PROJECT, "someNotebookName", "someImageName", "someDescription", String.format(AUDIT_MESSAGE, "someImageName"));
+
+        verify(requestId).put(USER.toLowerCase(), "someUuid");
+        verifyNoMoreInteractions(imageExploratoryService, requestId);
+    }
+
+    @Test
+    public void createImageWithException() {
+        doThrow(new ResourceAlreadyExistException("Image with name is already exist"))
+                .when(imageExploratoryService).createImage(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/image")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getExploratoryImageCreateFormDTO()));
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(imageExploratoryService).createImage(getUserInfo(), PROJECT, "someNotebookName", "someImageName", "someDescription", String.format(AUDIT_MESSAGE, "someImageName"));
+        verifyNoMoreInteractions(imageExploratoryService);
+        verifyZeroInteractions(requestId);
+    }
+
+    @Test
+    public void getImages() {
+        when(imageExploratoryService.getNotFailedImages(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(getImageList());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/image")
+                .queryParam("docker_image", "someDockerImage")
+                .queryParam("project", "someProject")
+                .queryParam("endpoint", "someEndpoint")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getImageList(), response.readEntity(new GenericType<List<ImageInfoRecord>>() {
+        }));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(imageExploratoryService).getNotFailedImages(USER.toLowerCase(), "someDockerImage", "someProject", "someEndpoint");
+        verifyNoMoreInteractions(imageExploratoryService);
+    }
+
+    @Test
+    public void getImagesWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(imageExploratoryService.getNotFailedImages(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(getImageList());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/image")
+                .queryParam("docker_image", "someDockerImage")
+                .queryParam("project", "someProject")
+                .queryParam("endpoint", "someEndpoint")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getImageList(), response.readEntity(new GenericType<List<ImageInfoRecord>>() {
+        }));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(imageExploratoryService).getNotFailedImages(USER.toLowerCase(), "someDockerImage", "someProject", "someEndpoint");
+        verifyNoMoreInteractions(imageExploratoryService);
+    }
+
+    @Test
+    public void getImage() {
+        when(imageExploratoryService.getImage(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(getImageList().get(0));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/image/someName")
+                .queryParam("project", "someProject")
+                .queryParam("endpoint", "someEndpoint")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getImageList().get(0), response.readEntity(ImageInfoRecord.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(imageExploratoryService).getImage(USER.toLowerCase(), "someName", "someProject", "someEndpoint");
+        verifyNoMoreInteractions(imageExploratoryService);
+    }
+
+    @Test
+    public void getImageWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(imageExploratoryService.getImage(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(getImageList().get(0));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/image/someName")
+                .queryParam("project", "someProject")
+                .queryParam("endpoint", "someEndpoint")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getImageList().get(0), response.readEntity(ImageInfoRecord.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(imageExploratoryService).getImage(USER.toLowerCase(), "someName", "someProject", "someEndpoint");
+        verifyNoMoreInteractions(imageExploratoryService);
+    }
+
+    @Test
+    public void getAllImagesForProject() {
+        when(imageExploratoryService.getImagesForProject(anyString())).thenReturn(getImageList());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/image/all")
+                .queryParam("project", "someProject")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getImageList(), response.readEntity(new GenericType<List<ImageInfoRecord>>() {
+        }));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(imageExploratoryService).getImagesForProject("someProject");
+        verifyNoMoreInteractions(imageExploratoryService);
+    }
+
+    @Test
+    public void getAllImagesForNullProject() {
+        when(imageExploratoryService.getImagesForProject(anyString())).thenReturn(getImageList());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/image/all")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(imageExploratoryService, never()).getImagesForProject(anyString());
+        verifyNoMoreInteractions(imageExploratoryService);
+    }
+
+    @Test
+    public void getImageWithException() {
+        doThrow(new ResourceNotFoundException("Image with name was not found for user"))
+                .when(imageExploratoryService).getImage(anyString(), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/image/someName")
+                .queryParam("project", "someProject")
+                .queryParam("endpoint", "someEndpoint")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_NOT_FOUND, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(imageExploratoryService).getImage(USER.toLowerCase(), "someName", "someProject", "someEndpoint");
+        verifyNoMoreInteractions(imageExploratoryService);
+    }
+
+    private ExploratoryImageCreateFormDTO getExploratoryImageCreateFormDTO() {
+        ExploratoryImageCreateFormDTO eicfDto = new ExploratoryImageCreateFormDTO("someImageName", "someDescription");
+        eicfDto.setNotebookName("someNotebookName");
+        eicfDto.setProjectName(PROJECT);
+        return eicfDto;
+    }
+
+    private List<ImageInfoRecord> getImageList() {
+        ImageInfoRecord imageInfoRecord = new ImageInfoRecord("someName", "someDescription", "someProject", "someEndpoint", "someUser", "someApp",
+                "someFullName", ImageStatus.CREATED);
+        return Collections.singletonList(imageInfoRecord);
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/InfrastructureInfoResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/InfrastructureInfoResourceTest.java
new file mode 100644
index 0000000..52b09b3
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/InfrastructureInfoResourceTest.java
@@ -0,0 +1,205 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.HealthStatusPageDTO;
+import com.epam.datalab.backendapi.service.InfrastructureInfoService;
+import com.epam.datalab.dto.InfrastructureMetaInfoDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class InfrastructureInfoResourceTest extends TestBase {
+
+    private InfrastructureInfoService infrastructureInfoService = mock(InfrastructureInfoService.class);
+
+    @Rule
+    public final ResourceTestRule resources =
+            getResourceTestRuleInstance(new InfrastructureInfoResource(infrastructureInfoService));
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Test
+    public void status() {
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verifyZeroInteractions(infrastructureInfoService);
+    }
+
+    @Test
+    public void statusWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verifyZeroInteractions(infrastructureInfoService);
+    }
+
+    @Test
+    public void healthStatus() {
+        HealthStatusPageDTO hspDto = getHealthStatusPageDTO();
+        when(infrastructureInfoService.getHeathStatus(any(UserInfo.class))).thenReturn(hspDto);
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/status")
+                .queryParam("full", "1")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(hspDto.getStatus(), response.readEntity(HealthStatusPageDTO.class).getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(infrastructureInfoService).getHeathStatus(refEq(getUserInfo()));
+        verifyNoMoreInteractions(infrastructureInfoService);
+    }
+
+    @Test
+    public void healthStatusWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        HealthStatusPageDTO hspDto = getHealthStatusPageDTO();
+        when(infrastructureInfoService.getHeathStatus(any(UserInfo.class))).thenReturn(hspDto);
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/status")
+                .queryParam("full", "1")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(hspDto.getStatus(), response.readEntity(HealthStatusPageDTO.class).getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(infrastructureInfoService).getHeathStatus(refEq(getUserInfo()));
+        verifyNoMoreInteractions(infrastructureInfoService);
+    }
+
+    @Test
+    public void healthStatusWithDefaultQueryParam() {
+        HealthStatusPageDTO hspDto = getHealthStatusPageDTO();
+        when(infrastructureInfoService.getHeathStatus(any(UserInfo.class))).thenReturn(hspDto);
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/status")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(hspDto.getStatus(), response.readEntity(HealthStatusPageDTO.class).getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(infrastructureInfoService).getHeathStatus(refEq(getUserInfo()));
+        verifyNoMoreInteractions(infrastructureInfoService);
+    }
+
+    @Test
+    public void healthStatusWithException() {
+        doThrow(new DatalabException("Could not return status of resources for user"))
+                .when(infrastructureInfoService).getHeathStatus(any(UserInfo.class));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/status")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(infrastructureInfoService).getHeathStatus(refEq(getUserInfo()));
+        verifyNoMoreInteractions(infrastructureInfoService);
+    }
+
+
+    @Test
+    public void getUserResourcesWithException() {
+        doThrow(new DatalabException("Could not load list of provisioned resources for user"))
+                .when(infrastructureInfoService).getUserResources(any(UserInfo.class));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/info")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(infrastructureInfoService).getUserResources(any());
+        verifyNoMoreInteractions(infrastructureInfoService);
+    }
+
+    @Test
+    public void getInfrastructureMeta() {
+
+        when(infrastructureInfoService.getInfrastructureMetaInfo()).thenReturn(
+                InfrastructureMetaInfoDTO.builder()
+                        .version("1.0").build());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure/meta")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        final InfrastructureMetaInfoDTO infrastructureMetaInfoDTO =
+                response.readEntity(InfrastructureMetaInfoDTO.class);
+        assertEquals("1.0", infrastructureMetaInfoDTO.getVersion());
+    }
+
+    private HealthStatusPageDTO getHealthStatusPageDTO() {
+        return HealthStatusPageDTO.builder()
+                .status("someStatus")
+                .build();
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/InfrastructureTemplateResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/InfrastructureTemplateResourceTest.java
new file mode 100644
index 0000000..bfa9472
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/InfrastructureTemplateResourceTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.InfrastructureTemplateService;
+import com.epam.datalab.dto.base.computational.FullComputationalTemplate;
+import com.epam.datalab.dto.imagemetadata.ComputationalMetadataDTO;
+import com.epam.datalab.dto.imagemetadata.ExploratoryMetadataDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class InfrastructureTemplateResourceTest extends TestBase {
+
+	private InfrastructureTemplateService infrastructureTemplateService = mock(InfrastructureTemplateService.class);
+
+	@Rule
+	public final ResourceTestRule resources =
+			getResourceTestRuleInstance(new InfrastructureTemplateResource(infrastructureTemplateService));
+
+	@Before
+	public void setup() throws AuthenticationException {
+		authSetup();
+	}
+
+	@Test
+	public void getComputationalTemplates() {
+		FullComputationalTemplate fullComputationalTemplate =
+				new FullComputationalTemplate(new ComputationalMetadataDTO());
+		when(infrastructureTemplateService.getComputationalTemplates(any(UserInfo.class), anyString(), anyString()))
+				.thenReturn(Collections.singletonList(fullComputationalTemplate));
+		final Response response = resources.getJerseyTest()
+				.target("/infrastructure_templates/test/endpoint/computational_templates")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.get();
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test", "endpoint");
+		verifyNoMoreInteractions(infrastructureTemplateService);
+	}
+
+	@Test
+	public void getComputationalTemplatesWithFailedAuth() throws AuthenticationException {
+		authFailSetup();
+		FullComputationalTemplate fullComputationalTemplate =
+				new FullComputationalTemplate(new ComputationalMetadataDTO());
+		when(infrastructureTemplateService.getComputationalTemplates(any(UserInfo.class), anyString(), anyString()))
+				.thenReturn(Collections.singletonList(fullComputationalTemplate));
+		final Response response = resources.getJerseyTest()
+				.target("/infrastructure_templates/test/endpoint/computational_templates")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.get();
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test", "endpoint");
+		verifyNoMoreInteractions(infrastructureTemplateService);
+	}
+
+	@Test
+	public void getComputationalTemplatesWithException() {
+		doThrow(new DatalabException("Could not load list of computational templates for user"))
+				.when(infrastructureTemplateService).getComputationalTemplates(any(UserInfo.class), anyString(), anyString());
+		final Response response = resources.getJerseyTest()
+				.target("/infrastructure_templates/test/endpoint/computational_templates")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.get();
+
+		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test", "endpoint");
+		verifyNoMoreInteractions(infrastructureTemplateService);
+	}
+
+	@Test
+	public void getExploratoryTemplates() {
+		ExploratoryMetadataDTO exploratoryMetadataDTO =
+				new ExploratoryMetadataDTO("someImageName");
+		when(infrastructureTemplateService.getExploratoryTemplates(any(UserInfo.class), anyString(), anyString()))
+				.thenReturn(Collections.singletonList(exploratoryMetadataDTO));
+		final Response response = resources.getJerseyTest()
+				.target("/infrastructure_templates/test/endpoint/exploratory_templates")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.get();
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertEquals(Collections.singletonList(exploratoryMetadataDTO),
+				response.readEntity(new GenericType<List<ExploratoryMetadataDTO>>() {
+				}));
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test", "endpoint");
+		verifyNoMoreInteractions(infrastructureTemplateService);
+	}
+
+	@Test
+	public void getExploratoryTemplatesWithFailedAuth() throws AuthenticationException {
+		authFailSetup();
+		ExploratoryMetadataDTO exploratoryMetadataDTO =
+				new ExploratoryMetadataDTO("someImageName");
+		when(infrastructureTemplateService.getExploratoryTemplates(any(UserInfo.class), anyString(), anyString()))
+				.thenReturn(Collections.singletonList(exploratoryMetadataDTO));
+		final Response response = resources.getJerseyTest()
+				.target("/infrastructure_templates/test/endpoint/exploratory_templates")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.get();
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertEquals(Collections.singletonList(exploratoryMetadataDTO),
+				response.readEntity(new GenericType<List<ExploratoryMetadataDTO>>() {
+				}));
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test", "endpoint");
+		verifyNoMoreInteractions(infrastructureTemplateService);
+	}
+
+
+	@Test
+	public void getExploratoryTemplatesWithException() {
+		doThrow(new DatalabException("Could not load list of exploratory templates for user"))
+				.when(infrastructureTemplateService).getExploratoryTemplates(any(UserInfo.class), anyString(), anyString());
+		final Response response = resources.getJerseyTest()
+				.target("/infrastructure_templates/test/endpoint/exploratory_templates")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.get();
+
+		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test", "endpoint");
+		verifyNoMoreInteractions(infrastructureTemplateService);
+	}
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/KeycloakResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/KeycloakResourceTest.java
new file mode 100644
index 0000000..9f3dac6
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/KeycloakResourceTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.SecurityDAO;
+import com.epam.datalab.backendapi.service.KeycloakService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.representations.AccessTokenResponse;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class KeycloakResourceTest extends TestBase {
+    private SecurityService securityService = mock(SecurityService.class);
+    private SelfServiceApplicationConfiguration configuration = mock(SelfServiceApplicationConfiguration.class, RETURNS_DEEP_STUBS);
+    private SecurityDAO securityDAO = mock(SecurityDAO.class);
+    private KeycloakService keycloakService = mock(KeycloakService.class);
+
+    @Rule
+    public final ResourceTestRule resources = getResourceTestRuleInstance(
+            new KeycloakResource(securityService, configuration, securityDAO, keycloakService));
+
+    @Test
+    public void refreshAccessToken() {
+        when(keycloakService.generateAccessToken(anyString())).thenReturn(mock(AccessTokenResponse.class));
+
+        final Response response = resources.getJerseyTest()
+                .target("oauth/refresh/" + "refresh_token")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(""));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+        verify(keycloakService).generateAccessToken(anyString());
+        verifyNoMoreInteractions(keycloakService);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/LibExploratoryResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/LibExploratoryResourceTest.java
new file mode 100644
index 0000000..d291698
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/LibExploratoryResourceTest.java
@@ -0,0 +1,443 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.resources.dto.LibInfoRecord;
+import com.epam.datalab.backendapi.resources.dto.LibInstallFormDTO;
+import com.epam.datalab.backendapi.resources.dto.LibKey;
+import com.epam.datalab.backendapi.resources.dto.LibraryDTO;
+import com.epam.datalab.backendapi.resources.dto.LibraryStatus;
+import com.epam.datalab.backendapi.resources.dto.SearchLibsFormDTO;
+import com.epam.datalab.backendapi.service.ExternalLibraryService;
+import com.epam.datalab.backendapi.service.LibraryService;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.dto.exploratory.LibInstallDTO;
+import com.epam.datalab.dto.exploratory.LibraryInstallDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.bson.Document;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static java.util.Collections.singletonList;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.anyListOf;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class LibExploratoryResourceTest extends TestBase {
+    private static final String AUDIT_MESSAGE = "Install libs: %s";
+    private static final String LIB_GROUP = "group";
+    private static final String LIB_NAME = "name";
+    private static final String LIB_VERSION = "version";
+    private static final String EXPLORATORY_NAME = "explName";
+    private static final String PROJECT = "projectName";
+    private static final String COMPUTATIONAL_NAME = "compName";
+    private static final String UUID = "uid";
+    private ExploratoryDAO exploratoryDAO = mock(ExploratoryDAO.class);
+    private LibraryService libraryService = mock(LibraryService.class);
+    private RESTService provisioningService = mock(RESTService.class);
+    private ExternalLibraryService externalLibraryService = mock(ExternalLibraryService.class);
+    private RequestId requestId = mock(RequestId.class);
+
+    @Rule
+    public final ResourceTestRule resources = getResourceTestRuleInstance(
+            new LibExploratoryResource(exploratoryDAO, libraryService, externalLibraryService));
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Test
+    public void getComputeLibGroupList() {
+        when(libraryService.getComputeLibGroups()).thenReturn(Collections.emptyList());
+
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/lib-groups/compute")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(libraryService).getComputeLibGroups();
+        verifyNoMoreInteractions(libraryService);
+    }
+
+    @Test
+    public void getExploratoryLibGroupList() {
+        when(libraryService.getExploratoryLibGroups(any(UserInfo.class), anyString(), anyString())).thenReturn(Collections.emptyList());
+
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/lib-groups/exploratory")
+                .queryParam("project", "projectName")
+                .queryParam("exploratory", "explName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(libraryService).getExploratoryLibGroups(getUserInfo(), "projectName", "explName");
+        verifyNoMoreInteractions(libraryService);
+    }
+
+    @Test
+    public void getLibList() {
+        when(libraryService.getLibs(anyString(), anyString(), anyString(), anyString())).thenReturn(getDocuments());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/lib_list")
+                .queryParam("project_name", "projectName")
+                .queryParam("exploratory_name", "explName")
+                .queryParam("computational_name", "compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getDocuments(), response.readEntity(new GenericType<List<Document>>() {
+        }));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(libraryService).getLibs(USER.toLowerCase(), "projectName", "explName", "compName");
+        verifyNoMoreInteractions(libraryService);
+    }
+
+    @Test
+    public void getLibListWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(libraryService.getLibs(anyString(), anyString(), anyString(), anyString())).thenReturn(getDocuments());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/lib_list")
+                .queryParam("project_name", "projectName")
+                .queryParam("exploratory_name", "explName")
+                .queryParam("computational_name", "compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getDocuments(), response.readEntity(new GenericType<List<Document>>() {
+        }));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(libraryService).getLibs(USER.toLowerCase(), "projectName", "explName", "compName");
+        verifyNoMoreInteractions(libraryService);
+    }
+
+    @Test
+    public void getLibListWithException() {
+        doThrow(new DatalabException("Cannot load installed libraries"))
+                .when(libraryService).getLibs(anyString(), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/lib_list")
+                .queryParam("project_name", "projectName")
+                .queryParam("exploratory_name", "explName")
+                .queryParam("computational_name", "compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(libraryService).getLibs(USER.toLowerCase(), "projectName", "explName", "compName");
+        verifyNoMoreInteractions(libraryService);
+    }
+
+    @Test
+    public void getLibListFormatted() {
+        when(libraryService.getLibInfo(anyString(), anyString(), anyString())).thenReturn(getLibInfoRecords());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/lib_list/formatted")
+                .queryParam("exploratory_name", "explName")
+                .queryParam("project_name", "projectName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(libraryService).getLibInfo(USER.toLowerCase(), "projectName", "explName");
+        verifyNoMoreInteractions(libraryService);
+    }
+
+    @Test
+    public void getLibListFormattedWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(libraryService.getLibInfo(anyString(), anyString(), anyString())).thenReturn(getLibInfoRecords());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/lib_list/formatted")
+                .queryParam("exploratory_name", "explName")
+                .queryParam("project_name", "projectName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(libraryService).getLibInfo(USER.toLowerCase(), "projectName", "explName");
+        verifyNoMoreInteractions(libraryService);
+    }
+
+    @Test
+    public void getLibListFormattedWithException() {
+        doThrow(new DatalabException("Cannot load  formatted list of installed libraries"))
+                .when(libraryService).getLibInfo(anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/lib_list/formatted")
+                .queryParam("exploratory_name", "explName")
+                .queryParam("project_name", "projectName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(libraryService).getLibInfo(USER.toLowerCase(), "projectName", "explName");
+        verifyNoMoreInteractions(libraryService);
+    }
+
+    @Test
+    public void libInstall() {
+        List<LibInstallDTO> libInstallDTOS = singletonList(new LibInstallDTO(LIB_GROUP, LIB_NAME, LIB_VERSION));
+        when(libraryService.installComputationalLibs(any(UserInfo.class), anyString(), anyString(),
+                anyString(), anyListOf(LibInstallDTO.class), anyString())).thenReturn(UUID);
+        LibInstallFormDTO libInstallFormDTO = new LibInstallFormDTO();
+        libInstallFormDTO.setComputationalName(COMPUTATIONAL_NAME);
+        libInstallFormDTO.setNotebookName(EXPLORATORY_NAME);
+        libInstallFormDTO.setProject(PROJECT);
+        libInstallFormDTO.setLibs(libInstallDTOS);
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/lib_install")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(libInstallFormDTO));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+        assertEquals(UUID, response.readEntity(String.class));
+
+        verify(libraryService).installComputationalLibs(refEq(getUserInfo()), eq(PROJECT),
+                eq(EXPLORATORY_NAME), eq(COMPUTATIONAL_NAME), eq(libInstallDTOS), eq(getAuditInfo(libInstallDTOS)));
+        verifyNoMoreInteractions(libraryService);
+        verifyZeroInteractions(provisioningService, requestId);
+    }
+
+
+    @Test
+    public void libInstallWithoutComputational() {
+        List<LibInstallDTO> libInstallDTOS = singletonList(new LibInstallDTO(LIB_GROUP, LIB_NAME, LIB_VERSION));
+        when(libraryService.installExploratoryLibs(any(UserInfo.class), anyString(), anyString(), anyListOf(LibInstallDTO.class), anyString())).thenReturn(UUID);
+        LibInstallFormDTO libInstallFormDTO = new LibInstallFormDTO();
+        libInstallFormDTO.setNotebookName(EXPLORATORY_NAME);
+        libInstallFormDTO.setLibs(libInstallDTOS);
+        libInstallFormDTO.setProject(PROJECT);
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/lib_install")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(libInstallFormDTO));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+        assertEquals(UUID, response.readEntity(String.class));
+
+        verify(libraryService).installExploratoryLibs(refEq(getUserInfo()), eq(PROJECT),
+                eq(EXPLORATORY_NAME), eq(libInstallDTOS), eq(getAuditInfo(libInstallDTOS)));
+        verifyNoMoreInteractions(libraryService);
+        verifyZeroInteractions(provisioningService, requestId);
+    }
+
+    @Test
+    public void getLibraryListWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(getUserInstanceDto());
+        SearchLibsFormDTO searchLibsFormDTO = new SearchLibsFormDTO();
+        searchLibsFormDTO.setComputationalName("compName");
+        searchLibsFormDTO.setNotebookName("explName");
+        searchLibsFormDTO.setGroup("someGroup");
+        searchLibsFormDTO.setStartWith("someText");
+        searchLibsFormDTO.setProjectName("projectName");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/search/lib_list")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(searchLibsFormDTO));
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER.toLowerCase(), "projectName", "explName", "compName");
+        verifyNoMoreInteractions(exploratoryDAO);
+    }
+
+    @Test
+    public void getLibraryListWithException() {
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(getUserInstanceDto());
+        SearchLibsFormDTO searchLibsFormDTO = new SearchLibsFormDTO();
+        searchLibsFormDTO.setComputationalName("compName");
+        searchLibsFormDTO.setNotebookName("explName");
+        searchLibsFormDTO.setGroup("someGroup");
+        searchLibsFormDTO.setStartWith("someText");
+        searchLibsFormDTO.setProjectName("projectName");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/search/lib_list")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(searchLibsFormDTO));
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER.toLowerCase(), "projectName", "explName", "compName");
+        verifyNoMoreInteractions(exploratoryDAO);
+    }
+
+    @Test
+    public void getLibraryListWithoutComputationalWithException() {
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString()))
+                .thenReturn(getUserInstanceDto());
+        SearchLibsFormDTO searchLibsFormDTO = new SearchLibsFormDTO();
+        searchLibsFormDTO.setComputationalName("");
+        searchLibsFormDTO.setNotebookName("explName");
+        searchLibsFormDTO.setGroup("someGroup");
+        searchLibsFormDTO.setStartWith("someText");
+        searchLibsFormDTO.setProjectName("projectName");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/search/lib_list")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(searchLibsFormDTO));
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER.toLowerCase(), "projectName", "explName");
+        verifyNoMoreInteractions(exploratoryDAO);
+    }
+
+    @Test
+    public void getMavenArtifact() {
+        when(externalLibraryService.getLibrary(anyString(), anyString(), anyString())).thenReturn(libraryDto());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/search/lib_list/maven")
+                .queryParam("artifact", "group:artifact:version")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+        final LibraryDTO libraryDTO = response.readEntity(LibraryDTO.class);
+        assertEquals("test", libraryDTO.getName());
+        assertEquals("1.0", libraryDTO.getVersion());
+
+        verify(externalLibraryService).getLibrary("group", "artifact", "version");
+        verifyNoMoreInteractions(externalLibraryService);
+    }
+
+    @Test
+    public void getMavenArtifactWithValidationException() {
+        when(externalLibraryService.getLibrary(anyString(), anyString(), anyString())).thenReturn(libraryDto());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/search/lib_list/maven")
+                .queryParam("artifact", "group:artifact")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        assertEquals("{\"errors\":[\"query param artifact Wrong library name format. Should be <groupId>:<artifactId>:<versionId>\"]}",
+                response.readEntity(String.class));
+
+        verifyZeroInteractions(externalLibraryService);
+    }
+
+    private LibraryDTO libraryDto() {
+        return new LibraryDTO(
+                "test", "1.0");
+    }
+
+    private UserInstanceDTO getUserInstanceDto() {
+        UserComputationalResource ucResource = new UserComputationalResource();
+        ucResource.setComputationalName("compName");
+        return new UserInstanceDTO()
+                .withUser(USER)
+                .withExploratoryName("explName")
+                .withProject(PROJECT)
+                .withResources(singletonList(ucResource));
+    }
+
+    private List<Document> getDocuments() {
+        return singletonList(new Document());
+    }
+
+    private List<LibInfoRecord> getLibInfoRecords() {
+        return singletonList(new LibInfoRecord(
+                new LibKey(), singletonList(new LibraryStatus())));
+    }
+
+    private LibraryInstallDTO getLibraryInstallDTO() {
+        return new LibraryInstallDTO().withComputationalName("compName");
+    }
+
+    private String getAuditInfo(List<LibInstallDTO> libs) {
+        return String.format(AUDIT_MESSAGE, libs
+                .stream()
+                .map(LibInstallDTO::getName)
+                .collect(Collectors.joining(", ")));
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ProjectResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ProjectResourceTest.java
new file mode 100644
index 0000000..47e0c4c
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ProjectResourceTest.java
@@ -0,0 +1,292 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.BudgetDTO;
+import com.epam.datalab.backendapi.domain.CreateProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectEndpointDTO;
+import com.epam.datalab.backendapi.domain.UpdateProjectBudgetDTO;
+import com.epam.datalab.backendapi.domain.UpdateProjectDTO;
+import com.epam.datalab.backendapi.resources.dto.KeysDTO;
+import com.epam.datalab.backendapi.resources.dto.ProjectActionFormDTO;
+import com.epam.datalab.backendapi.service.AccessKeyService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceConflictException;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.anyList;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class ProjectResourceTest extends TestBase {
+
+    private static final String PROJECT_NAME = "DATALAB";
+
+    private final ProjectService projectService = mock(ProjectService.class);
+    private final AccessKeyService keyService = mock(AccessKeyService.class);
+
+    @Rule
+    public final ResourceTestRule resources = getResourceTestRuleInstance(
+            new ProjectResource(projectService, keyService));
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Test
+    public void createProject() {
+        CreateProjectDTO createProjectDTO = returnCreateProjectDTO();
+        final Response response = resources.getJerseyTest()
+                .target("project")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(createProjectDTO));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        verify(projectService).create(getUserInfo(), prepareProjectDTO(createProjectDTO), createProjectDTO.getName());
+        verifyNoMoreInteractions(projectService);
+    }
+
+    @Test
+    public void createExistingProject() {
+        CreateProjectDTO createProjectDTO = returnCreateProjectDTO();
+        doThrow(new ResourceConflictException("Project with passed name already exist in system"))
+                .when(projectService).create(any(UserInfo.class), any(ProjectDTO.class), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("project")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(createProjectDTO));
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        verify(projectService).create(getUserInfo(), prepareProjectDTO(createProjectDTO), createProjectDTO.getName());
+        verifyNoMoreInteractions(projectService);
+    }
+
+    @Test
+    public void startProject() {
+        final Response response = resources.getJerseyTest()
+                .target("project/start")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getProjectActionDTO()));
+
+        assertEquals(HttpStatus.SC_ACCEPTED, response.getStatus());
+        verify(projectService).start(getUserInfo(), Collections.singletonList("https://localhost:8083/"), PROJECT_NAME);
+        verifyNoMoreInteractions(projectService);
+    }
+
+    @Test
+    public void stopProject() {
+        final Response response = resources.getJerseyTest()
+                .target("project/stop")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getProjectActionDTO()));
+
+        assertEquals(HttpStatus.SC_ACCEPTED, response.getStatus());
+        verify(projectService).stopWithResources(getUserInfo(), Collections.singletonList("https://localhost:8083/"), PROJECT_NAME);
+        verifyNoMoreInteractions(projectService);
+    }
+
+    @Test
+    public void getProject() {
+        when(projectService.get(anyString())).thenReturn(ProjectDTO.builder().name(PROJECT_NAME).build());
+
+        final Response response = resources.getJerseyTest()
+                .target("project/" + PROJECT_NAME)
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+        verify(projectService).get(PROJECT_NAME);
+        verifyNoMoreInteractions(projectService);
+    }
+
+    @Test
+    public void getProjects() {
+        when(projectService.getProjects(any(UserInfo.class))).thenReturn(Collections.singletonList(ProjectDTO.builder().name(PROJECT_NAME).build()));
+
+        final Response response = resources.getJerseyTest()
+                .target("project")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+        verify(projectService).getProjects(getUserInfo());
+        verifyNoMoreInteractions(projectService);
+    }
+
+    @Test
+    public void getUserProjects() {
+        when(projectService.getUserProjects(getUserInfo(), false)).thenReturn(Collections.singletonList(ProjectDTO.builder().name(PROJECT_NAME).build()));
+
+        final Response response = resources.getJerseyTest()
+                .target("project/me")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+        verify(projectService).getUserProjects(getUserInfo(), Boolean.FALSE);
+        verifyNoMoreInteractions(projectService);
+    }
+
+    @Test
+    public void updateProject() {
+        doNothing().when(projectService).update(any(UserInfo.class), any(UpdateProjectDTO.class), anyString());
+
+        final Response response = resources.getJerseyTest()
+                .target("project")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .put(Entity.json(prepareUpdateProjectDTO()));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        verify(projectService).update(getUserInfo(), prepareUpdateProjectDTO(), PROJECT_NAME);
+        verifyNoMoreInteractions(projectService);
+    }
+
+    @Test
+    public void removeProjectEndpoint() {
+        doNothing().when(projectService).terminateEndpoint(any(UserInfo.class), anyList(), anyString());
+
+        final Response response = resources.getJerseyTest()
+                .target("project/terminate")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(prepareProjectActionFormDTO()));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        verify(projectService).terminateEndpoint(getUserInfo(), prepareProjectActionFormDTO().getEndpoints(), prepareProjectActionFormDTO().getProjectName());
+        verifyNoMoreInteractions(projectService);
+    }
+
+    @Test
+    public void updateBudget() {
+        doNothing().when(projectService).updateBudget(any(UserInfo.class), anyList());
+
+        final Response response = resources.getJerseyTest()
+                .target("project/budget")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .put(Entity.json((prepareUpdateProjectBudgetDTOs())));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+
+        verify(projectService).updateBudget(getUserInfo(), prepareUpdateProjectBudgetDTOs());
+        verifyNoMoreInteractions(projectService);
+    }
+
+    @Test
+    public void generate() {
+        when(keyService.generateKeys(any(UserInfo.class))).thenReturn(new KeysDTO("somePublicKey", "somePrivateKey", "user"));
+
+        final Response response = resources.getJerseyTest()
+                .target("/project/keys")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(""));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(keyService).generateKeys(getUserInfo());
+        verifyNoMoreInteractions(keyService);
+    }
+
+    @Test
+    public void generateKeysWithException() {
+        doThrow(new DatalabException("Can not generate private/public key pair due to"))
+                .when(keyService).generateKeys(any(UserInfo.class));
+
+        final Response response = resources.getJerseyTest()
+                .target("/project/keys")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(""));
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(keyService).generateKeys(getUserInfo());
+        verifyNoMoreInteractions(keyService);
+    }
+
+    private CreateProjectDTO returnCreateProjectDTO() {
+        return new CreateProjectDTO(PROJECT_NAME, Collections.emptySet(), Collections.emptySet(), "ssh-testKey", "testTag");
+    }
+
+    private ProjectDTO prepareProjectDTO(CreateProjectDTO createProjectDTO) {
+        List<ProjectEndpointDTO> projectEndpointDTOS = createProjectDTO.getEndpoints()
+                .stream()
+                .map(e -> new ProjectEndpointDTO(e, UserInstanceStatus.CREATING, null))
+                .collect(Collectors.toList());
+
+        return new ProjectDTO(createProjectDTO.getName(), createProjectDTO.getGroups(), createProjectDTO.getKey(), createProjectDTO.getTag(),
+                new BudgetDTO(), projectEndpointDTOS, createProjectDTO.isSharedImageEnabled());
+    }
+
+    private ProjectActionFormDTO getProjectActionDTO() {
+        return new ProjectActionFormDTO(PROJECT_NAME, Collections.singletonList("https://localhost:8083/"));
+    }
+
+    private UpdateProjectDTO prepareUpdateProjectDTO() {
+        return new UpdateProjectDTO(PROJECT_NAME, Collections.emptySet(), Collections.emptySet(), Boolean.TRUE);
+    }
+
+    private ProjectActionFormDTO prepareProjectActionFormDTO() {
+        return new ProjectActionFormDTO(PROJECT_NAME, Collections.singletonList("https://localhost:8083/"));
+    }
+
+    private List<UpdateProjectBudgetDTO> prepareUpdateProjectBudgetDTOs() {
+        return Collections.singletonList(new UpdateProjectBudgetDTO(PROJECT_NAME, 123, Boolean.FALSE));
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/SchedulerJobResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/SchedulerJobResourceTest.java
new file mode 100644
index 0000000..36758fb
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/SchedulerJobResourceTest.java
@@ -0,0 +1,341 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.service.SchedulerJobService;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.exceptions.ResourceInappropriateStateException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.model.scheduler.SchedulerJobData;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class SchedulerJobResourceTest extends TestBase {
+
+    private SchedulerJobService schedulerJobService = mock(SchedulerJobService.class);
+
+    @Rule
+    public final ResourceTestRule resources =
+            getResourceTestRuleInstance(new SchedulerJobResource(schedulerJobService));
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Test
+    public void updateExploratoryScheduler() {
+        doNothing().when(schedulerJobService)
+                .updateExploratorySchedulerData(any(UserInfo.class), anyString(), anyString(), any(SchedulerJobDTO.class));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getSchedulerJobDTO()));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).updateExploratorySchedulerData(getUserInfo(), "projectName",
+                "explName", getSchedulerJobDTO());
+        verifyNoMoreInteractions(schedulerJobService);
+    }
+
+    @Test
+    public void updateExploratorySchedulerWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        doNothing().when(schedulerJobService)
+                .updateExploratorySchedulerData(any(UserInfo.class), anyString(), anyString(), any(SchedulerJobDTO.class));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName")
+                .request()
+                .header("Authorization", String.join(" ", "Bearer", TOKEN))
+                .post(Entity.json(getSchedulerJobDTO()));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).updateExploratorySchedulerData(getUserInfo(), "projectName",
+                "explName", getSchedulerJobDTO());
+        verifyNoMoreInteractions(schedulerJobService);
+    }
+
+    @Test
+    public void updateExploratorySchedulerWithException() {
+        doThrow(new ResourceInappropriateStateException("Can't create/update scheduler for user instance with status"))
+                .when(schedulerJobService).updateExploratorySchedulerData(any(UserInfo.class), anyString(), anyString(),
+                any(SchedulerJobDTO.class));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getSchedulerJobDTO()));
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).updateExploratorySchedulerData(getUserInfo(), "projectName",
+                "explName", getSchedulerJobDTO());
+        verifyNoMoreInteractions(schedulerJobService);
+    }
+
+    @Test
+    public void upsertComputationalScheduler() {
+        doNothing().when(schedulerJobService)
+                .updateComputationalSchedulerData(any(UserInfo.class), anyString(), anyString(), anyString(), any(SchedulerJobDTO.class));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName/compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getSchedulerJobDTO()));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).updateComputationalSchedulerData(getUserInfo(), "projectName",
+                "explName", "compName", getSchedulerJobDTO());
+        verifyNoMoreInteractions(schedulerJobService);
+    }
+
+    @Test
+    public void upsertComputationalSchedulerWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        doNothing().when(schedulerJobService)
+                .updateComputationalSchedulerData(any(UserInfo.class), anyString(), anyString(), anyString(), any(SchedulerJobDTO.class));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName/compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getSchedulerJobDTO()));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).updateComputationalSchedulerData(getUserInfo(), "projectName",
+                "explName", "compName", getSchedulerJobDTO());
+        verifyNoMoreInteractions(schedulerJobService);
+    }
+
+    @Test
+    public void upsertComputationalSchedulerWithException() {
+        doThrow(new ResourceInappropriateStateException("Can't create/update scheduler for user instance with status"))
+                .when(schedulerJobService).updateComputationalSchedulerData(any(UserInfo.class), anyString(), anyString(),
+                anyString(), any(SchedulerJobDTO.class));
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName/compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getSchedulerJobDTO()));
+
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).updateComputationalSchedulerData(getUserInfo(), "projectName",
+                "explName", "compName", getSchedulerJobDTO());
+        verifyNoMoreInteractions(schedulerJobService);
+    }
+
+    @Test
+    public void fetchSchedulerJobForUserAndExploratory() {
+        when(schedulerJobService.fetchSchedulerJobForUserAndExploratory(anyString(), anyString(), anyString()))
+                .thenReturn(getSchedulerJobDTO());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getSchedulerJobDTO(), response.readEntity(SchedulerJobDTO.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).fetchSchedulerJobForUserAndExploratory(USER.toLowerCase(), "projectName", "explName");
+        verifyNoMoreInteractions(schedulerJobService);
+    }
+
+    @Test
+    public void fetchSchedulerJobForUserAndExploratoryWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(schedulerJobService.fetchSchedulerJobForUserAndExploratory(anyString(), anyString(), anyString()))
+                .thenReturn(getSchedulerJobDTO());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getSchedulerJobDTO(), response.readEntity(SchedulerJobDTO.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).fetchSchedulerJobForUserAndExploratory(USER.toLowerCase(), "projectName", "explName");
+        verifyNoMoreInteractions(schedulerJobService);
+    }
+
+
+    @Test
+    public void fetchSchedulerJobForUserAndExploratoryWithException() {
+        doThrow(new ResourceNotFoundException("Scheduler job data not found for user with exploratory"))
+                .when(schedulerJobService).fetchSchedulerJobForUserAndExploratory(anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_NOT_FOUND, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).fetchSchedulerJobForUserAndExploratory(USER.toLowerCase(), "projectName", "explName");
+        verifyNoMoreInteractions(schedulerJobService);
+    }
+
+    @Test
+    public void fetchSchedulerJobForComputationalResource() {
+        when(schedulerJobService.fetchSchedulerJobForComputationalResource(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(getSchedulerJobDTO());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName/compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getSchedulerJobDTO(), response.readEntity(SchedulerJobDTO.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).fetchSchedulerJobForComputationalResource(USER.toLowerCase(), "projectName",
+                "explName", "compName");
+        verifyNoMoreInteractions(schedulerJobService);
+    }
+
+    @Test
+    public void fetchSchedulerJobForComputationalResourceWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(schedulerJobService.fetchSchedulerJobForComputationalResource(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(getSchedulerJobDTO());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName/compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getSchedulerJobDTO(), response.readEntity(SchedulerJobDTO.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).fetchSchedulerJobForComputationalResource(USER.toLowerCase(), "projectName",
+                "explName", "compName");
+        verifyNoMoreInteractions(schedulerJobService);
+    }
+
+    @Test
+    public void fetchSchedulerJobForComputationalResourceWithException() {
+        doThrow(new ResourceNotFoundException("Scheduler job data not found for user with exploratory with " +
+                "computational resource")).when(schedulerJobService)
+                .fetchSchedulerJobForComputationalResource(anyString(), anyString(), anyString(), anyString());
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName/compName")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_NOT_FOUND, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).fetchSchedulerJobForComputationalResource(USER.toLowerCase(), "projectName",
+                "explName", "compName");
+        verifyNoMoreInteractions(schedulerJobService);
+    }
+
+    @Test
+    public void testGetActiveSchedulers() {
+        when(schedulerJobService.getActiveSchedulers(anyString(), anyLong()))
+                .thenReturn(Collections.singletonList(new SchedulerJobData(USER, "exploratoryName", null,
+                        "project", getSchedulerJobDTO())));
+        final long minuteOffset = 10L;
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment/scheduler/active")
+                .queryParam("minuteOffset", minuteOffset)
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+        final List<SchedulerJobData> activeSchedulers = response.readEntity(new GenericType<List<SchedulerJobData>>() {
+        });
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(1, activeSchedulers.size());
+        assertEquals(Collections.singletonList(new SchedulerJobData(USER, "exploratoryName", null,
+                "project", getSchedulerJobDTO())), activeSchedulers);
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(schedulerJobService).getActiveSchedulers(USER.toLowerCase(), minuteOffset);
+        verifyNoMoreInteractions(schedulerJobService);
+
+    }
+
+    private SchedulerJobDTO getSchedulerJobDTO() {
+        SchedulerJobDTO schedulerJobDTO = new SchedulerJobDTO();
+        schedulerJobDTO.setTimeZoneOffset(OffsetDateTime.now(ZoneId.systemDefault()).getOffset());
+        schedulerJobDTO.setBeginDate(LocalDate.now());
+        schedulerJobDTO.setFinishDate(LocalDate.now().plusDays(1));
+        schedulerJobDTO.setStartTime(LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        schedulerJobDTO.setEndTime(LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        schedulerJobDTO.setTerminateDateTime(
+                LocalDateTime.of(LocalDate.now(), LocalTime.now().truncatedTo(ChronoUnit.MINUTES)));
+        schedulerJobDTO.setStartDaysRepeat(Arrays.asList(DayOfWeek.values()));
+        schedulerJobDTO.setStopDaysRepeat(Arrays.asList(DayOfWeek.values()));
+        schedulerJobDTO.setSyncStartRequired(false);
+        return schedulerJobDTO;
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/SystemInfoResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/SystemInfoResourceTest.java
new file mode 100644
index 0000000..aa75bac
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/SystemInfoResourceTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.backendapi.resources.dto.SystemInfoDto;
+import com.epam.datalab.backendapi.service.SystemInfoService;
+import com.epam.datalab.model.systeminfo.DiskInfo;
+import com.epam.datalab.model.systeminfo.MemoryInfo;
+import com.epam.datalab.model.systeminfo.OsInfo;
+import com.epam.datalab.model.systeminfo.ProcessorInfo;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class SystemInfoResourceTest extends TestBase {
+
+    private SystemInfoService systemInfoService = mock(SystemInfoService.class);
+
+    @Rule
+    public final ResourceTestRule resources = getResourceTestRuleInstance(new SystemInfoResource(systemInfoService));
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Test
+    public void getSystemInfo() {
+        when(systemInfoService.getSystemInfo()).thenReturn(getSystemInfoDto());
+        final Response response = resources.getJerseyTest()
+                .target("/sysinfo")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(systemInfoService).getSystemInfo();
+        verifyNoMoreInteractions(systemInfoService);
+    }
+
+    @Test
+    public void getSystemInfoWithFailedAuth() throws AuthenticationException {
+        authFailSetup();
+        when(systemInfoService.getSystemInfo()).thenReturn(getSystemInfoDto());
+        final Response response = resources.getJerseyTest()
+                .target("/sysinfo")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verifyZeroInteractions(systemInfoService);
+    }
+
+    private SystemInfoDto getSystemInfoDto() {
+        OsInfo osInfo = OsInfo.builder()
+                .family(System.getProperty("os.name"))
+                .buildNumber(System.getProperty("os.version"))
+                .build();
+        ProcessorInfo processorInfo = ProcessorInfo.builder().build();
+        MemoryInfo memoryInfo = MemoryInfo.builder().build();
+        DiskInfo diskInfo = DiskInfo.builder().build();
+        return new SystemInfoDto(osInfo, processorInfo, memoryInfo, Collections.singletonList(diskInfo));
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/TestBase.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/TestBase.java
new file mode 100644
index 0000000..43169b1
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/TestBase.java
@@ -0,0 +1,92 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.rest.mappers.ResourceNotFoundExceptionMapper;
+import io.dropwizard.auth.AuthDynamicFeature;
+import io.dropwizard.auth.AuthValueFactoryProvider;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.Authorizer;
+import io.dropwizard.auth.oauth.OAuthCredentialAuthFilter;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
+import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
+
+import java.util.Optional;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class TestBase {
+
+    protected final String TOKEN = "TOKEN";
+    protected final String USER = "testUser";
+    protected final String ENDPOINT_NAME = "local";
+    protected final String ENDPOINT_URL = "http://localhost:8443/";
+    protected final String ENDPOINT_ACCOUNT = "account";
+    protected final String ENDPOINT_TAG = "tag";
+
+    @SuppressWarnings("unchecked")
+    private static Authenticator<String, UserInfo> authenticator = mock(Authenticator.class);
+    @SuppressWarnings("unchecked")
+    private static Authorizer<UserInfo> authorizer = mock(Authorizer.class);
+
+    protected <T> ResourceTestRule getResourceTestRuleInstance(T resourceInstance) {
+        return ResourceTestRule.builder()
+                .bootstrapLogging(false)
+                .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
+                .addProvider(new AuthDynamicFeature(new OAuthCredentialAuthFilter.Builder<UserInfo>()
+                        .setAuthenticator(authenticator)
+                        .setAuthorizer(authorizer)
+                        .setRealm("SUPER SECRET STUFF")
+                        .setPrefix("Bearer")
+                        .buildAuthFilter()))
+                .addProvider(RolesAllowedDynamicFeature.class)
+                .addProvider(new ResourceNotFoundExceptionMapper())
+                .addProvider(new AuthValueFactoryProvider.Binder<>(UserInfo.class))
+                .addProvider(MultiPartFeature.class)
+                .addResource(resourceInstance)
+                .build();
+    }
+
+    protected void authSetup() throws AuthenticationException {
+        when(authenticator.authenticate(TOKEN)).thenReturn(Optional.of(getUserInfo()));
+        when(authorizer.authorize(any(), any())).thenReturn(true);
+    }
+
+    protected void authFailSetup() throws AuthenticationException {
+        when(authenticator.authenticate(TOKEN)).thenReturn(Optional.of(getUserInfo()));
+        when(authorizer.authorize(any(), any())).thenReturn(false);
+    }
+
+    protected UserInfo getUserInfo() {
+        return new UserInfo(USER, TOKEN);
+    }
+
+    protected EndpointDTO getEndpointDTO() {
+        return new EndpointDTO(ENDPOINT_NAME, ENDPOINT_URL, ENDPOINT_ACCOUNT, ENDPOINT_TAG, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/UserGroupResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/UserGroupResourceTest.java
new file mode 100644
index 0000000..1aba319
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/UserGroupResourceTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.ProjectDAO;
+import com.epam.datalab.backendapi.resources.dto.GroupDTO;
+import com.epam.datalab.backendapi.resources.dto.UpdateGroupDTO;
+import com.epam.datalab.backendapi.resources.dto.UserGroupDto;
+import com.epam.datalab.backendapi.service.UserGroupService;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class UserGroupResourceTest extends TestBase {
+
+    private static final String USER = "user";
+    private static final String ROLE_ID = "id";
+    private static final String ROLE_DESCRIPTION = "description";
+    private static final String GROUP = "group";
+    private UserGroupService userGroupService = mock(UserGroupService.class);
+    private ProjectDAO projectDAO = mock(ProjectDAO.class);
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Rule
+    public final ResourceTestRule resources =
+            getResourceTestRuleInstance(new UserGroupResource(userGroupService));
+
+    @Test
+    public void createGroup() {
+
+        final Response response = resources.getJerseyTest()
+                .target("/group")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getCreateGroupDto(GROUP, Collections.singletonMap(ROLE_ID, ROLE_DESCRIPTION))));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+
+        verify(userGroupService).createGroup(getUserInfo(), GROUP, Collections.singleton(ROLE_ID), Collections.singleton(USER));
+        verifyNoMoreInteractions(userGroupService);
+    }
+
+    @Test
+    public void createGroupWhenGroupNameIsEmpty() {
+
+        final Response response = resources.getJerseyTest()
+                .target("/group")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getCreateGroupDto("", Collections.singletonMap(ROLE_ID, ROLE_DESCRIPTION))));
+
+        assertEquals(HttpStatus.SC_UNPROCESSABLE_ENTITY, response.getStatus());
+
+        verifyZeroInteractions(userGroupService);
+    }
+
+    @Test
+    public void createGroupWhenRoleIdIsEmpty() {
+
+        final Response response = resources.getJerseyTest()
+                .target("/group")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getCreateGroupDto(GROUP, Collections.emptyMap())));
+
+        assertEquals(HttpStatus.SC_UNPROCESSABLE_ENTITY, response.getStatus());
+
+        verifyZeroInteractions(userGroupService);
+    }
+
+    @Test
+    public void updateGroup() {
+
+        final Response response = resources.getJerseyTest()
+                .target("/group")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .put(Entity.json(getUpdaeGroupDto(GROUP, Collections.singletonMap(ROLE_ID, ROLE_DESCRIPTION), Collections.singleton(USER))));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+
+        verify(userGroupService).updateGroup(getUserInfo(), GROUP, Collections.singletonMap(ROLE_ID, ROLE_DESCRIPTION), Collections.singleton(USER));
+        verifyNoMoreInteractions(userGroupService);
+    }
+
+    @Test
+    public void getGroups() {
+        when(userGroupService.getAggregatedRolesByGroup(any(UserInfo.class))).thenReturn(Collections.singletonList(getUserGroup()));
+
+        final Response response = resources.getJerseyTest()
+                .target("/group")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        final List<UserGroupDto> actualRoles = response.readEntity(new GenericType<List<UserGroupDto>>() {
+        });
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(GROUP, actualRoles.get(0).getGroup());
+        assertTrue(actualRoles.get(0).getRoles().isEmpty());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(userGroupService).getAggregatedRolesByGroup(getUserInfo());
+        verifyNoMoreInteractions(userGroupService);
+    }
+
+    @Test
+    public void deleteGroup() {
+        final Response response = resources.getJerseyTest()
+                .target("/group/" + GROUP)
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .delete();
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+
+
+        verify(userGroupService).removeGroup(getUserInfo(), GROUP);
+        verifyNoMoreInteractions(userGroupService);
+    }
+
+    private UserGroupDto getUserGroup() {
+        return new UserGroupDto(GROUP, Collections.emptyList(), Collections.emptySet());
+    }
+
+    private GroupDTO getCreateGroupDto(String group, Map<String, String> roleIds) {
+        final GroupDTO dto = new GroupDTO();
+        dto.setName(group);
+        dto.setRoleIds(roleIds);
+        dto.setUsers(Collections.singleton(USER));
+        return dto;
+    }
+
+    private UpdateGroupDTO getUpdaeGroupDto(String group, Map<String, String> roles, Set<String> users) {
+        UpdateGroupDTO updateGroupDTO = new UpdateGroupDTO();
+        updateGroupDTO.setName(group);
+        updateGroupDTO.setRoles(roles);
+        updateGroupDTO.setUsers(users);
+        return updateGroupDTO;
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/UserRoleResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/UserRoleResourceTest.java
new file mode 100644
index 0000000..19f0630
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/UserRoleResourceTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.backendapi.resources.dto.UserRoleDto;
+import com.epam.datalab.backendapi.service.UserRoleService;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class UserRoleResourceTest extends TestBase {
+
+
+    private static final String USER = "user";
+    private static final String ROLE_ID = "id";
+
+    private UserRoleService rolesService = mock(UserRoleService.class);
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Rule
+    public final ResourceTestRule resources =
+            getResourceTestRuleInstance(new UserRoleResource(rolesService));
+
+
+    @Test
+    public void getRoles() {
+        when(rolesService.getUserRoles()).thenReturn(Collections.singletonList(getUserRole()));
+
+        final Response response = resources.getJerseyTest()
+                .target("/role")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .get();
+
+        final List<UserRoleDto> actualRoles = response.readEntity(new GenericType<List<UserRoleDto>>() {
+        });
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(ROLE_ID, actualRoles.get(0).getId());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(rolesService).getUserRoles();
+        verifyNoMoreInteractions(rolesService);
+    }
+
+    @Test
+    public void createRole() {
+
+        final Response response = resources.getJerseyTest()
+                .target("/role")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getUserRole()));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+
+        verify(rolesService).createRole(refEq(getUserRole()));
+        verifyNoMoreInteractions(rolesService);
+    }
+
+    private UserRoleDto getUserRole() {
+        final UserRoleDto userRoleDto = new UserRoleDto();
+        userRoleDto.setId(ROLE_ID);
+        return userRoleDto;
+    }
+
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/UserSettingsResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/UserSettingsResourceTest.java
new file mode 100644
index 0000000..104ae34
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/UserSettingsResourceTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.UserDTO;
+import com.epam.datalab.backendapi.service.UserSettingService;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.testing.junit.ResourceTestRule;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpStatus;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import static java.util.Collections.singletonList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.refEq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class UserSettingsResourceTest extends TestBase {
+
+	private UserSettingService userSettingService = mock(UserSettingService.class);
+
+	@Rule
+	public final ResourceTestRule resources =
+			getResourceTestRuleInstance(new UserSettingsResource(userSettingService));
+
+	@Before
+	public void setup() throws AuthenticationException {
+		authSetup();
+	}
+
+	@Test
+	public void getSettings() {
+		when(userSettingService.getUISettings(any(UserInfo.class))).thenReturn("someSettings");
+		final Response response = resources.getJerseyTest()
+				.target("/user/settings")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.get();
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertEquals("someSettings", response.readEntity(String.class));
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(userSettingService).getUISettings(refEq(getUserInfo()));
+		verifyNoMoreInteractions(userSettingService);
+	}
+
+	@Test
+	public void getSettingsWithFailedAuth() throws AuthenticationException {
+		authFailSetup();
+		when(userSettingService.getUISettings(any(UserInfo.class))).thenReturn("someSettings");
+		final Response response = resources.getJerseyTest()
+				.target("/user/settings")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.get();
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertEquals("someSettings", response.readEntity(String.class));
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(userSettingService).getUISettings(refEq(getUserInfo()));
+		verifyNoMoreInteractions(userSettingService);
+	}
+
+	@Test
+	public void saveSettings() {
+		doNothing().when(userSettingService).saveUISettings(any(UserInfo.class), anyString());
+		final Response response = resources.getJerseyTest()
+				.target("/user/settings")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.post(Entity.json("someSettings"));
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(userSettingService).saveUISettings(refEq(getUserInfo()), eq("someSettings"));
+		verifyNoMoreInteractions(userSettingService);
+	}
+
+	@Test
+	public void saveSettingsWithFailedAuth() throws AuthenticationException {
+		authFailSetup();
+		doNothing().when(userSettingService).saveUISettings(any(UserInfo.class), anyString());
+		final Response response = resources.getJerseyTest()
+				.target("/user/settings")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.post(Entity.json("someSettings"));
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(userSettingService).saveUISettings(refEq(getUserInfo()), eq("someSettings"));
+		verifyNoMoreInteractions(userSettingService);
+	}
+
+	@Test
+	public void saveSettingsWithException() {
+		doThrow(new RuntimeException()).when(userSettingService).saveUISettings(any(UserInfo.class), anyString());
+		final Response response = resources.getJerseyTest()
+				.target("/user/settings")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.post(Entity.json("someSettings"));
+
+		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+		assertTrue(response.readEntity(String.class).contains("{\"code\":500,\"message\":\"There was an error " +
+				"processing your request. It has been logged"));
+		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(userSettingService).saveUISettings(refEq(getUserInfo()), eq("someSettings"));
+		verifyNoMoreInteractions(userSettingService);
+	}
+
+	@Test
+	public void saveAllowedBudget() {
+		doNothing().when(userSettingService).saveUISettings(any(UserInfo.class), anyString());
+		final Response response = resources.getJerseyTest()
+				.target("/user/settings/budget")
+				.request()
+				.header("Authorization", "Bearer " + TOKEN)
+				.put(Entity.json(singletonList(new UserDTO(USER, 10, UserDTO.Status.ACTIVE))));
+
+		assertEquals(HttpStatus.SC_OK, response.getStatus());
+		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+		verify(userSettingService).updateUsersBudget(singletonList(new UserDTO(USER, 10, UserDTO.Status.ACTIVE)));
+		verifyNoMoreInteractions(userSettingService);
+	}
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/roles/UserRolesTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/roles/UserRolesTest.java
new file mode 100644
index 0000000..cd9b490
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/roles/UserRolesTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.datalab.backendapi.roles;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.SecurityDAO;
+import com.mongodb.client.FindIterable;
+import com.mongodb.client.MongoCursor;
+import org.bson.Document;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class UserRolesTest {
+
+    @Mock
+    private SecurityDAO dao;
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void checkAccess() {
+        UserInfo userInfoDev = new UserInfo("developer", "token123");
+        userInfoDev.addRole("dev");
+        List<String> shapes1 = new ArrayList<>();
+        shapes1.add("shape_1");
+        shapes1.add("shape_2");
+        shapes1.add("shape_3");
+        ArrayList<String> devGroup = new ArrayList<>();
+        devGroup.add("dev");
+        Document doc1 = new Document().append("exploratory_shapes", shapes1).append("groups", devGroup);
+
+        UserInfo userInfoTest = new UserInfo("tester", "token321");
+        userInfoTest.addRole("test");
+        List<String> shapes2 = new ArrayList<>();
+        shapes2.add("shape_2");
+        shapes2.add("shape_3");
+        ArrayList<String> testGroup = new ArrayList<>();
+        testGroup.add("test");
+        Document doc2 = new Document().append("exploratory_shapes", shapes2).append("groups", testGroup);
+
+        MongoCursor cursor = mock(MongoCursor.class);
+
+        FindIterable mockIterable = mock(FindIterable.class);
+
+        when(dao.getRoles()).thenReturn(mockIterable);
+        when(mockIterable.iterator()).thenReturn(cursor);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(doc1).thenReturn(doc2);
+        UserRoles.initialize(dao, true);
+
+        assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "shape_1", userInfoDev.getRoles()));
+        assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "shape_2", userInfoDev.getRoles()));
+        assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "shape_3", userInfoDev.getRoles()));
+        assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "someShape", userInfoDev.getRoles()));
+
+        assertFalse(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "shape_1", userInfoTest.getRoles()));
+        assertFalse(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "shape_2", userInfoTest.getRoles()));
+        assertFalse(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "shape_3", userInfoTest.getRoles()));
+        assertTrue(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "someShape", userInfoTest.getRoles()));
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/schedulers/CheckApplicationQuoteSchedulerTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/schedulers/CheckApplicationQuoteSchedulerTest.java
new file mode 100644
index 0000000..dc05a1a
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/schedulers/CheckApplicationQuoteSchedulerTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.datalab.backendapi.schedulers;
+
+import com.epam.datalab.backendapi.dao.BillingDAO;
+import com.epam.datalab.backendapi.service.EnvironmentService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.quartz.JobExecutionContext;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CheckApplicationQuoteSchedulerTest {
+
+    @Mock
+    private BillingDAO billingDAO;
+    @Mock
+    private EnvironmentService environmentService;
+    @Mock
+    private JobExecutionContext jobExecutionContext;
+    @InjectMocks
+    private CheckApplicationQuoteScheduler checkApplicationQuoteScheduler;
+
+    @Test
+    public void testWhenQuoteNotReached() {
+        when(billingDAO.isBillingQuoteReached()).thenReturn(false);
+
+        checkApplicationQuoteScheduler.execute(jobExecutionContext);
+
+        verify(billingDAO).isBillingQuoteReached();
+        verifyNoMoreInteractions(billingDAO);
+        verifyZeroInteractions(environmentService);
+    }
+
+    @Test
+    public void testWhenQuoteReached() {
+        when(billingDAO.isBillingQuoteReached()).thenReturn(true);
+
+        checkApplicationQuoteScheduler.execute(jobExecutionContext);
+
+        verify(billingDAO).isBillingQuoteReached();
+        verify(environmentService).stopAll();
+        verifyNoMoreInteractions(billingDAO, environmentService);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/schedulers/CheckUserQuoteSchedulerTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/schedulers/CheckUserQuoteSchedulerTest.java
new file mode 100644
index 0000000..8b21ba4
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/schedulers/CheckUserQuoteSchedulerTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.datalab.backendapi.schedulers;
+
+import com.epam.datalab.backendapi.dao.BillingDAO;
+import com.epam.datalab.backendapi.resources.dto.UserDTO;
+import com.epam.datalab.backendapi.service.EnvironmentService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.quartz.JobExecutionContext;
+
+import java.util.Collections;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CheckUserQuoteSchedulerTest {
+
+    private static final String USER = "test";
+    @Mock
+    private BillingDAO billingDAO;
+    @Mock
+    private EnvironmentService environmentService;
+    @Mock
+    private JobExecutionContext jobExecutionContext;
+    @InjectMocks
+    private CheckUserQuoteScheduler checkUserQuoteScheduler;
+
+    @Test
+    public void testWhenUserQuoteReached() {
+        when(billingDAO.isUserQuoteReached(anyString())).thenReturn(true);
+        when(environmentService.getUsers()).thenReturn(Collections.singletonList(new UserDTO(USER, 1, UserDTO.Status.ACTIVE)));
+
+        checkUserQuoteScheduler.execute(jobExecutionContext);
+
+        verify(environmentService).getUsers();
+        verify(billingDAO).isUserQuoteReached(USER);
+        verify(environmentService).stopEnvironmentWithServiceAccount(USER);
+        verifyNoMoreInteractions(environmentService, billingDAO);
+        verifyZeroInteractions(jobExecutionContext);
+    }
+
+    @Test
+    public void testWhenUserQuoteNotReached() {
+        when(billingDAO.isUserQuoteReached(anyString())).thenReturn(false);
+        when(environmentService.getUsers()).thenReturn(Collections.singletonList(new UserDTO(USER, 1, UserDTO.Status.ACTIVE)));
+
+        checkUserQuoteScheduler.execute(jobExecutionContext);
+
+        verify(environmentService).getUsers();
+        verify(billingDAO).isUserQuoteReached(USER);
+        verify(environmentService, never()).stopEnvironmentWithServiceAccount(anyString());
+        verifyNoMoreInteractions(environmentService, billingDAO);
+        verifyZeroInteractions(jobExecutionContext);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/ApplicationSettingServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/ApplicationSettingServiceImplTest.java
new file mode 100644
index 0000000..166c73b
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/ApplicationSettingServiceImplTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.backendapi.dao.MongoSetting;
+import com.epam.datalab.backendapi.dao.SettingsDAO;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Collections;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ApplicationSettingServiceImplTest {
+
+    private static final long MAX_BUDGET = 10L;
+    @Mock
+    private SettingsDAO settingsDAO;
+    @InjectMocks
+    private ApplicationSettingServiceImpl applicationSettingService;
+
+    @Test
+    public void setMaxBudget() {
+
+        applicationSettingService.setMaxBudget(MAX_BUDGET);
+
+        verify(settingsDAO).setMaxBudget(MAX_BUDGET);
+        verifyNoMoreInteractions(settingsDAO);
+    }
+
+    @Test
+    public void getSettings() {
+        when(settingsDAO.getSettings()).thenReturn(Collections.singletonMap("key", "value"));
+        final Map<String, Object> settings = applicationSettingService.getSettings();
+        assertEquals(1, settings.size());
+        assertEquals("value", settings.get("key"));
+
+        verify(settingsDAO).getSettings();
+        verifyNoMoreInteractions(settingsDAO);
+    }
+
+    @Test
+    public void removeMaxBudget() {
+
+        applicationSettingService.removeMaxBudget();
+
+        verify(settingsDAO).removeSetting(MongoSetting.CONF_MAX_BUDGET);
+        verifyNoMoreInteractions(settingsDAO);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/KeycloakServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/KeycloakServiceImplTest.java
new file mode 100644
index 0000000..50992ec
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/KeycloakServiceImplTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.SecurityDAO;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.keycloak.representations.AccessTokenResponse;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class KeycloakServiceImplTest {
+    private static final String ACCESS_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJNUC15QVpENFdJRzloa" +
+            "np3R0RqQjdCeW9aNGpaV05QTjJ3X25uS1BkTnQ4In0.eyJqdGkiOiJlYTgzZTQ2OS0xNjFhLTQ1ZDUtYWI4YS1mZDUxYThmMzMwMzYiL" +
+            "CJleHAiOjE1NzA0NDQ1NTQsIm5iZiI6MCwiaWF0IjoxNTcwNDQzMzU0LCJpc3MiOiJodHRwOi8vNTIuMTEuNDUuMTE6ODA4MC9hdXRoL" +
+            "3JlYWxtcy9ETEFCX2JobGl2YSIsImF1ZCI6WyJwcm92aXNpb25pbmciLCJhY2NvdW50Il0sInN1YiI6ImRjNzczMThkLWYzN2UtNGNmO" +
+            "S1iMDgwLTU2ZTRjMWUwNDVhNSIsInR5cCI6IkJlYXJlciIsImF6cCI6InNzcyIsImF1dGhfdGltZSI6MTU3MDQ0MzMyOSwic2Vzc2lvb" +
+            "l9zdGF0ZSI6ImVkYTE3ODJjLTliZmItNDQ5Yy1hYWY1LWNhNzM5MDViMmI1NyIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZ" +
+            "XMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7InNzcyI6eyJyb2xlcyI6W" +
+            "yJ0ZXN0Il19LCJwcm92aXNpb25pbmciOnsicm9sZXMiOlsidGVzdCJdfSwiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3Vud" +
+            "CIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSIsImVtY" +
+            "WlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdCJ9.jXjqFP1xmG32NahYnw1spO7fhEyGiqeu0QdBYuo9" +
+            "y6TI8xlAy5EFQ_5SrW6UuzpZUhgCjStH3Qkk_xgLlbZ9IqnxwOmx1i8arlurKf1mY_rm2_C5JBxHdHio8in8yEMls8t-wQOT46kMJNC7" +
+            "4GUzuWWQxS1h6F1V6238rnT8_W27oFcG449ShOGOQ5Du4F9B4ur3Ns6j5oSduwUFlbY_rNpGurUmtFWXBaXM61CiezJPxXu5pHzWK6Xq" +
+            "Z1IkuEUaDDJdBf1OGi13toq88V7C-Pr7YlnyWlbZ7bw2VXAs3NAgtn_30KlgYwR9YUJ_AB5TP3u8kK0jY0vLPosuBZgKeA";
+    private static final String REFRESH_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImUyZjk0YjFmLTBhMjMtNGJi" +
+            "OS05NDUwLTdjNDQ4MTdjY2RkMCJ9.eyJqdGkiOiI0NmNiMzczMy1mM2IzLTRiYjItYmQyZC02N2FjNzg5N2VmNTUiLCJleHAiOjE1NzA" +
+            "0NDMzNTQsIm5iZiI6MCwiaWF0IjoxNTcwNDQzMzU0LCJpc3MiOiJodHRwOi8vNTIuMTEuNDUuMTE6ODA4MC9hdXRoL3JlYWxtcy9ETEF" +
+            "CX2JobGl2YSIsImF1ZCI6Imh0dHA6Ly81Mi4xMS40NS4xMTo4MDgwL2F1dGgvcmVhbG1zL0RMQUJfYmhsaXZhIiwic3ViIjoiZGM3NzM" +
+            "xOGQtZjM3ZS00Y2Y5LWIwODAtNTZlNGMxZTA0NWE1IiwidHlwIjoiUmVmcmVzaCIsImF6cCI6InNzcyIsImF1dGhfdGltZSI6MCwic2V" +
+            "zc2lvbl9zdGF0ZSI6ImVkYTE3ODJjLTliZmItNDQ5Yy1hYWY1LWNhNzM5MDViMmI1NyIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJ" +
+            "vZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsic3NzIjp7InJvbGVzIjpbInRlc3Q" +
+            "iXX0sInByb3Zpc2lvbmluZyI6eyJyb2xlcyI6WyJ0ZXN0Il19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWF" +
+            "uYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIn0.rzkrAprIt0-" +
+            "jD0h9ex3krzfu8UDcgnrRdocNFJmYa30";
+    @Mock
+    private Client httpClient;
+    @Mock
+    private SecurityDAO securityDAO;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private SelfServiceApplicationConfiguration conf;
+
+    private KeycloakServiceImpl keycloakService;
+
+    @Before
+    public void setUp() {
+        keycloakService = new KeycloakServiceImpl(httpClient, conf, securityDAO);
+    }
+
+    @Test
+    public void generateAccessToken() {
+        WebTarget webTarget = mock(WebTarget.class);
+        Invocation.Builder builder = mock(Invocation.Builder.class);
+        Response response = mock(Response.class);
+        Response.StatusType statusType = mock(Response.StatusType.class);
+        AccessTokenResponse tokenResponse = mock(AccessTokenResponse.class);
+
+        when(httpClient.target(anyString())).thenReturn(webTarget);
+        when(webTarget.request()).thenReturn(builder);
+        when(builder.header(any(), anyString())).thenReturn(builder);
+        when(builder.post(any())).thenReturn(response);
+        when(response.getStatusInfo()).thenReturn(statusType);
+        when(response.readEntity(AccessTokenResponse.class)).thenReturn(tokenResponse);
+        when(statusType.getFamily()).thenReturn(Response.Status.Family.SUCCESSFUL);
+        when(tokenResponse.getToken()).thenReturn(ACCESS_TOKEN);
+        doNothing().when(securityDAO).updateUser(anyString(), any(AccessTokenResponse.class));
+
+        keycloakService.generateAccessToken(REFRESH_TOKEN);
+
+        verify(httpClient).target(anyString());
+        verify(securityDAO).updateUser("test", tokenResponse);
+        verifyNoMoreInteractions(securityDAO, httpClient);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/ProjectServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/ProjectServiceImplTest.java
new file mode 100644
index 0000000..c52abf7
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/ProjectServiceImplTest.java
@@ -0,0 +1,426 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.ProjectDAO;
+import com.epam.datalab.backendapi.dao.UserGroupDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectEndpointDTO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.domain.UpdateProjectBudgetDTO;
+import com.epam.datalab.backendapi.resources.TestBase;
+import com.epam.datalab.backendapi.service.impl.ProjectServiceImpl;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.project.ProjectActionDTO;
+import com.epam.datalab.dto.project.ProjectCreateDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceConflictException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.rest.client.RESTService;
+import com.google.common.collect.Sets;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.anySet;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ProjectServiceImplTest extends TestBase {
+    private static final String CREATE_PRJ_API = "infrastructure/project/create";
+    private static final String TERMINATE_PRJ_API = "infrastructure/project/terminate";
+    private static final String START_PRJ_API = "infrastructure/project/start";
+    private static final String STOP_PRJ_API = "infrastructure/project/stop";
+
+    private static final String NAME1 = "name1";
+    private static final String NAME2 = "name2";
+    private static final String GROUP1 = "group1";
+    private static final String GROUP2 = "group2";
+    private static final String UUID = "uuid";
+
+    private static final List<UserInstanceStatus> notebookStatuses = Arrays.asList(
+            UserInstanceStatus.CREATING, UserInstanceStatus.STARTING, UserInstanceStatus.CREATING_IMAGE,
+            UserInstanceStatus.CONFIGURING, UserInstanceStatus.RECONFIGURING, UserInstanceStatus.STOPPING,
+            UserInstanceStatus.TERMINATING);
+    private static final UserInstanceStatus[] computeStatuses = {UserInstanceStatus.CREATING, UserInstanceStatus.CONFIGURING, UserInstanceStatus.STARTING,
+            UserInstanceStatus.RECONFIGURING, UserInstanceStatus.CREATING_IMAGE, UserInstanceStatus.STOPPING,
+            UserInstanceStatus.TERMINATING};
+
+    @Mock
+    private ProjectDAO projectDAO;
+    @Mock
+    private EndpointService endpointService;
+    @Mock
+    private RESTService provisioningService;
+    @Mock
+    private RequestBuilder requestBuilder;
+    @Mock
+    private RequestId requestId;
+    @Mock
+    private ExploratoryService exploratoryService;
+    @Mock
+    private ExploratoryDAO exploratoryDAO;
+    @Mock
+    private UserGroupDAO userGroupDao;
+    @Mock
+    private SelfServiceApplicationConfiguration configuration;
+    @InjectMocks
+    private ProjectServiceImpl projectService;
+
+    @Test
+    public void getProjects() {
+        List<ProjectDTO> projectsMock = getProjectDTOs();
+        when(projectDAO.getProjects()).thenReturn(projectsMock);
+
+        List<ProjectDTO> projects = projectService.getProjects();
+
+        assertEquals(projects, projectsMock);
+        verify(projectDAO).getProjects();
+        verifyNoMoreInteractions(projectDAO);
+    }
+
+    @Test
+    public void testGetProjects() {
+        List<ProjectDTO> projectsMock = getProjectDTOs();
+        when(projectDAO.getProjects()).thenReturn(projectsMock);
+
+        projectService.getProjects(getUserInfo());
+
+        verify(projectDAO).getProjects();
+        verifyNoMoreInteractions(projectDAO);
+    }
+
+    @Test
+    public void getUserProjects() {
+        List<ProjectDTO> projectsMock = Collections.singletonList(getProjectCreatingDTO());
+        when(projectDAO.getUserProjects(any(UserInfo.class), anyBoolean())).thenReturn(projectsMock);
+
+        List<ProjectDTO> projects = projectService.getUserProjects(getUserInfo(), Boolean.TRUE);
+
+        assertEquals(projectsMock, projects);
+        verify(projectDAO).getUserProjects(getUserInfo(), Boolean.TRUE);
+        verifyNoMoreInteractions(projectDAO);
+    }
+
+    @Test
+    public void getProjectsByEndpoint() {
+        List<ProjectDTO> projectsMock = Collections.singletonList(getProjectCreatingDTO());
+        when(projectDAO.getProjectsByEndpoint(anyString())).thenReturn(projectsMock);
+
+        List<ProjectDTO> projects = projectService.getProjectsByEndpoint(ENDPOINT_NAME);
+
+        assertEquals(projectsMock, projects);
+        verify(projectDAO).getProjectsByEndpoint(ENDPOINT_NAME);
+        verifyNoMoreInteractions(projectDAO);
+    }
+
+    @Test
+    public void create() {
+        when(projectDAO.get(anyString())).thenReturn(Optional.empty());
+        when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
+        when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
+        when(requestBuilder.newProjectCreate(any(UserInfo.class), any(ProjectDTO.class), any(EndpointDTO.class))).thenReturn(newProjectCreate());
+
+        ProjectDTO projectDTO = getProjectCreatingDTO();
+        projectService.create(getUserInfo(), projectDTO, projectDTO.getName());
+
+        verify(projectDAO).get(NAME1);
+        verify(projectDAO).create(projectDTO);
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(requestBuilder).newProjectCreate(getUserInfo(), projectDTO, getEndpointDTO());
+        verify(provisioningService).post(ENDPOINT_URL + CREATE_PRJ_API, TOKEN, newProjectCreate(), String.class);
+        verify(requestId).put(USER.toLowerCase(), UUID);
+        verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder);
+    }
+
+    @Test(expected = ResourceConflictException.class)
+    public void createWithException() {
+        when(projectDAO.get(anyString())).thenReturn(Optional.of(getProjectCreatingDTO()));
+
+        ProjectDTO projectDTO = getProjectCreatingDTO();
+        projectService.create(getUserInfo(), projectDTO, projectDTO.getName());
+
+        verify(projectDAO).get(NAME1);
+        verifyNoMoreInteractions(projectDAO);
+    }
+
+    @Test
+    public void get() {
+        ProjectDTO projectMock = getProjectCreatingDTO();
+        when(projectDAO.get(anyString())).thenReturn(Optional.of(projectMock));
+
+        ProjectDTO project = projectService.get(NAME1);
+
+        assertEquals(projectMock, project);
+        verify(projectDAO).get(NAME1);
+        verifyNoMoreInteractions(projectDAO);
+    }
+
+    @Test(expected = ResourceNotFoundException.class)
+    public void getWithException() {
+        when(projectDAO.get(anyString())).thenReturn(Optional.empty());
+
+        projectService.get(NAME1);
+
+        verify(projectDAO).get(NAME1);
+        verifyNoMoreInteractions(projectDAO);
+    }
+
+    @Test
+    public void terminateEndpoint() {
+        when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
+        when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
+        when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
+
+        projectService.terminateEndpoint(getUserInfo(), ENDPOINT_NAME, NAME1);
+
+        verify(exploratoryService).updateProjectExploratoryStatuses(getUserInfo(), NAME1, ENDPOINT_NAME, UserInstanceStatus.TERMINATING);
+        verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.TERMINATING);
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).post(ENDPOINT_URL + TERMINATE_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
+        verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
+        verify(requestId).put(USER.toLowerCase(), UUID);
+        verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, exploratoryService);
+    }
+
+    @Test
+    public void terminateEndpointWithException() {
+        when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
+        when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
+        when(provisioningService.post(anyString(), anyString(), any(), any())).thenThrow(new DatalabException("Exception message"));
+
+        projectService.terminateEndpoint(getUserInfo(), ENDPOINT_NAME, NAME1);
+
+        verify(exploratoryService).updateProjectExploratoryStatuses(getUserInfo(), NAME1, ENDPOINT_NAME, UserInstanceStatus.TERMINATING);
+        verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.TERMINATING);
+        verify(projectDAO).updateStatus(NAME1, ProjectDTO.Status.FAILED);
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).post(ENDPOINT_URL + TERMINATE_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
+        verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
+        verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, exploratoryService);
+    }
+
+    @Test
+    public void testTerminateEndpoint() {
+        when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
+        when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
+        when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
+        when(projectDAO.get(anyString())).thenReturn(Optional.of(getProjectRunningDTO()));
+        when(exploratoryDAO.fetchProjectEndpointExploratoriesWhereStatusIn(anyString(), anyListOf(String.class), anyListOf(UserInstanceStatus.class)))
+                .thenReturn(Collections.emptyList());
+
+        projectService.terminateEndpoint(getUserInfo(), Collections.singletonList(ENDPOINT_NAME), NAME1);
+
+        verify(projectDAO).get(NAME1);
+        verify(exploratoryDAO).fetchProjectEndpointExploratoriesWhereStatusIn(NAME1, Collections.singletonList(ENDPOINT_NAME), notebookStatuses, computeStatuses);
+        verify(exploratoryService).updateProjectExploratoryStatuses(getUserInfo(), NAME1, ENDPOINT_NAME, UserInstanceStatus.TERMINATING);
+        verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.TERMINATING);
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).post(ENDPOINT_URL + TERMINATE_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
+        verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
+        verify(requestId).put(USER.toLowerCase(), UUID);
+        verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, exploratoryDAO);
+    }
+
+    @Test(expected = ResourceConflictException.class)
+    public void testTerminateEndpointWithException1() {
+        when(projectDAO.get(anyString())).thenReturn(Optional.of(getProjectCreatingDTO()));
+
+        projectService.terminateEndpoint(getUserInfo(), Collections.singletonList(ENDPOINT_NAME), NAME1);
+
+        verify(projectDAO).get(NAME1);
+        verifyNoMoreInteractions(projectDAO);
+    }
+
+    @Test
+    public void start() {
+        when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
+        when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
+        when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
+
+        projectService.start(getUserInfo(), ENDPOINT_NAME, NAME1);
+
+        verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.STARTING);
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).post(ENDPOINT_URL + START_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
+        verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
+        verify(requestId).put(USER.toLowerCase(), UUID);
+        verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, requestId);
+    }
+
+    @Test
+    public void testStart() {
+        when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
+        when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
+        when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
+
+        projectService.start(getUserInfo(), Collections.singletonList(ENDPOINT_NAME), NAME1);
+
+        verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.STARTING);
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).post(ENDPOINT_URL + START_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
+        verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
+        verify(requestId).put(USER.toLowerCase(), UUID);
+        verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, requestId);
+    }
+
+    @Test
+    public void stop() {
+        when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
+        when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
+        when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
+
+        projectService.stop(getUserInfo(), ENDPOINT_NAME, NAME1, null);
+
+        verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.STOPPING);
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).post(ENDPOINT_URL + STOP_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
+        verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
+        verify(requestId).put(USER.toLowerCase(), UUID);
+        verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, requestId);
+    }
+
+    @Test
+    public void stopWithResources() {
+        when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
+        when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
+        when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
+        when(projectDAO.get(anyString())).thenReturn(Optional.of(getProjectRunningDTO()));
+        when(exploratoryDAO.fetchProjectEndpointExploratoriesWhereStatusIn(anyString(), anyListOf(String.class), anyListOf(UserInstanceStatus.class)))
+                .thenReturn(Collections.emptyList());
+
+        projectService.stopWithResources(getUserInfo(), Collections.singletonList(ENDPOINT_NAME), NAME1);
+
+        verify(projectDAO).get(NAME1);
+        verify(exploratoryDAO).fetchProjectEndpointExploratoriesWhereStatusIn(NAME1, Collections.singletonList(ENDPOINT_NAME), notebookStatuses, computeStatuses);
+        verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.STOPPING);
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).post(ENDPOINT_URL + STOP_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
+        verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
+        verify(requestId).put(USER.toLowerCase(), UUID);
+        verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, requestId);
+    }
+
+    @Test
+    public void update() {
+    }
+
+    @Test
+    public void updateBudget() {
+        projectService.updateBudget(getUserInfo(), Collections.singletonList(getUpdateProjectBudgetDTO()));
+
+        verify(projectDAO).updateBudget(NAME1, 10, true);
+        verifyNoMoreInteractions(projectDAO);
+    }
+
+    @Test
+    public void isAnyProjectAssigned() {
+        when(userGroupDao.getUserGroups(anyString())).thenReturn(Sets.newHashSet(GROUP1));
+        when(projectDAO.isAnyProjectAssigned(anySet())).thenReturn(Boolean.TRUE);
+
+        final boolean anyProjectAssigned = projectService.isAnyProjectAssigned(getUserInfo());
+
+        assertEquals(anyProjectAssigned, Boolean.TRUE);
+        verify(userGroupDao).getUserGroups(USER.toLowerCase());
+        verify(projectDAO).isAnyProjectAssigned(Sets.newHashSet(GROUP1));
+        verifyNoMoreInteractions(userGroupDao, projectDAO);
+    }
+
+    @Test
+    public void checkExploratoriesAndComputationalProgress() {
+        when(exploratoryDAO.fetchProjectEndpointExploratoriesWhereStatusIn(anyString(), anyListOf(String.class), anyListOf(UserInstanceStatus.class)))
+                .thenReturn(Collections.emptyList());
+
+        final boolean b = projectService.checkExploratoriesAndComputationalProgress(NAME1, Collections.singletonList(ENDPOINT_NAME));
+
+        assertEquals(b, Boolean.TRUE);
+        verify(exploratoryDAO).fetchProjectEndpointExploratoriesWhereStatusIn(NAME1, Collections.singletonList(ENDPOINT_NAME), notebookStatuses, computeStatuses);
+        verifyNoMoreInteractions(exploratoryDAO);
+    }
+
+    private List<ProjectDTO> getProjectDTOs() {
+        ProjectDTO project1 = ProjectDTO.builder()
+                .name(NAME1)
+                .groups(getGroup(GROUP1))
+                .build();
+        ProjectDTO project2 = ProjectDTO.builder()
+                .name(NAME2)
+                .groups(getGroup(GROUP2))
+                .build();
+        return Arrays.asList(project1, project2);
+    }
+
+    private ProjectDTO getProjectCreatingDTO() {
+        ProjectEndpointDTO projectEndpointDTO = new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.CREATING, null);
+        return ProjectDTO.builder()
+                .name(NAME1)
+                .groups(getGroup(GROUP1))
+                .endpoints(Collections.singletonList(projectEndpointDTO))
+                .build();
+    }
+
+    private ProjectDTO getProjectRunningDTO() {
+        ProjectEndpointDTO projectEndpointDTO = new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, null);
+        return ProjectDTO.builder()
+                .name(NAME1)
+                .groups(getGroup(GROUP1))
+                .endpoints(Collections.singletonList(projectEndpointDTO))
+                .build();
+    }
+
+    private Set<String> getGroup(String group) {
+        return Collections.singleton(group);
+    }
+
+    private ProjectCreateDTO newProjectCreate() {
+        return ProjectCreateDTO.builder()
+                .name(NAME1)
+                .endpoint(ENDPOINT_NAME)
+                .build();
+    }
+
+    private ProjectActionDTO getProjectActionDTO() {
+        return new ProjectActionDTO(NAME1, ENDPOINT_NAME);
+    }
+
+    private UpdateProjectBudgetDTO getUpdateProjectBudgetDTO() {
+        return new UpdateProjectBudgetDTO(NAME1, 10, true);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/SecurityServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/SecurityServiceImplTest.java
new file mode 100644
index 0000000..1050d00
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/SecurityServiceImplTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.SecurityDAO;
+import com.epam.datalab.backendapi.domain.AuditActionEnum;
+import com.epam.datalab.backendapi.domain.AuditDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.keycloak.representations.AccessTokenResponse;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SecurityServiceImplTest {
+
+    private static final String CODE = "code";
+    private static final String TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJNUC15QVpENFdJRzloanp3R0RqQjdCeW9aNGpaV05QTjJ3X25uS1BkTnQ4In0.eyJqdGkiOiJkN2U0MDk3Yi1hNjdlLTQxYWUtYjBiNC05MzE1YWFmOGZkMDciLCJleHAiOjE1OTkwNDI1ODgsIm5iZiI6MCwiaWF0IjoxNTk5MDM4OTg4LCJpc3MiOiJodHRwOi8vNTIuMTEuNDUuMTE6ODA4MC9hdXRoL3JlYWxtcy9ETEFCX2JobGl2YSIsImF1ZCI6WyJwcm92aXNpb25pbmciLCJhY2NvdW50Il0sInN1YiI6ImRjNzczMThkLWYzN2UtNGNmOS1iMDgwLTU2ZTRjMWUwNDVhNSIsInR5cCI6IkJlYXJlciIsImF6cCI6InNzcyIsImF1dGhfdGltZSI6MTU5OTAzODk4Nywic2Vzc2lvbl9zdGF0ZSI6Ijg2Njg3NzQ3LTNlOGUtNDhhYy1iMTE1LWM4ZDRmNzQ5M2M1ZSIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7InNzcyI6eyJyb2xlcyI6WyJ0ZXN0Il19LCJwcm92aXNpb25pbmciOnsicm9sZXMiOlsidGVzdCJdfSwiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdCIsImVtYWlsIjoidGVzdEBlcGFtLmNvbSJ9.cYXGXjHGOg2XKADNGuQSykb6aUc-_CC4cUaTJ9qVml0IZDPYcUF9H_iTB-vL67k5MpuM4mVpZWHYT9oJYuFKZoR5lPUmiHG3A8LWxZq4ALeTEqWzOdOn2hUsoPSVoaTG8nLqgOQFHAV8G66dD-0zy-8QheGwZznXZ2_lRvSIg-IYRj_vhv91AItNQQ2eXho7zAic_QiLQHo5vUIEOGcVQdRkiVXe-CZ9pe8lHw8tlKwLlHJj7ldv1YVi0m8f9Tztn2ylSoETwSXdmk09pLxzoFG1EP-EU5cDE5l_MDJIVdhGFJR8eLd8dyzFjThupSMwgWEr_iDmbZ4Q116sv8g4jw";
+    private static final String REFRESH_TOKEN = "refreshToken";
+    private static final String USERNAME = "test";
+
+    @Mock
+    private KeycloakService keycloakService;
+    @Mock
+    private SecurityDAO securityDAO;
+    @Mock
+    private AuditService auditService;
+
+    @InjectMocks
+    private SecurityServiceImpl securityService;
+
+    @Test
+    public void testGetUserInfo() {
+        AccessTokenResponse tokenResponse = mock(AccessTokenResponse.class);
+        when(tokenResponse.getToken()).thenReturn(TOKEN);
+        when(tokenResponse.getRefreshToken()).thenReturn(REFRESH_TOKEN);
+        when(keycloakService.getToken(anyString())).thenReturn(tokenResponse);
+
+        UserInfo actualUserInfo = securityService.getUserInfo(CODE);
+
+        assertEquals("UserInfo should be equal", getUserInfoWithRefreshToken(), actualUserInfo);
+        verify(keycloakService).getToken(CODE);
+        verify(securityDAO).saveUser(USERNAME, tokenResponse);
+        verify(auditService).save(getAuditDTO());
+        verifyNoMoreInteractions(keycloakService, securityDAO, auditService);
+    }
+
+    @Test
+    public void getUserInfoOffline() {
+        AccessTokenResponse tokenResponseFromDB = mock(AccessTokenResponse.class);
+        when(tokenResponseFromDB.getRefreshToken()).thenReturn(REFRESH_TOKEN);
+        when(securityDAO.getTokenResponse(anyString())).thenReturn(Optional.of(tokenResponseFromDB));
+        AccessTokenResponse tokenResponse = mock(AccessTokenResponse.class);
+        when(tokenResponse.getToken()).thenReturn(TOKEN);
+        when(keycloakService.refreshToken(anyString())).thenReturn(tokenResponse);
+
+        UserInfo actualUserInfoOffline = securityService.getUserInfoOffline(USERNAME);
+
+        assertEquals("UserInfo should be equal", getUserInfo(), actualUserInfoOffline);
+        verify(securityDAO).getTokenResponse(USERNAME);
+        verify(keycloakService).refreshToken(REFRESH_TOKEN);
+        verifyNoMoreInteractions(securityDAO, keycloakService);
+    }
+
+    @Test(expected = DatalabException.class)
+    public void getUserInfoOfflineWithException() {
+        when(securityDAO.getTokenResponse(anyString())).thenReturn(Optional.empty());
+
+        securityService.getUserInfoOffline(USERNAME);
+
+        verify(securityDAO).getTokenResponse(USERNAME);
+        verifyNoMoreInteractions(securityDAO, keycloakService);
+    }
+
+    @Test
+    public void getServiceAccountInfo() {
+        AccessTokenResponse tokenResponse = mock(AccessTokenResponse.class);
+        when(tokenResponse.getToken()).thenReturn(TOKEN);
+        when(keycloakService.generateServiceAccountToken()).thenReturn(tokenResponse);
+
+        UserInfo actualUserInfo = securityService.getServiceAccountInfo(USERNAME);
+
+        assertEquals("UserInfo should be equal", getUserInfo(), actualUserInfo);
+        verify(keycloakService).generateServiceAccountToken();
+        verifyNoMoreInteractions(keycloakService);
+    }
+
+
+    private UserInfo getUserInfo() {
+        return new UserInfo(USERNAME, TOKEN);
+    }
+
+    private UserInfo getUserInfoWithRefreshToken() {
+        UserInfo userInfo = new UserInfo(USERNAME, TOKEN);
+        userInfo.setRefreshToken(REFRESH_TOKEN);
+        return userInfo;
+    }
+
+    private AuditDTO getAuditDTO() {
+        return AuditDTO.builder()
+                .user(USERNAME)
+                .action(AuditActionEnum.LOG_IN)
+                .build();
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/TagServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/TagServiceImplTest.java
new file mode 100644
index 0000000..652d193
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/TagServiceImplTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.backendapi.resources.TestBase;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class TagServiceImplTest extends TestBase {
+
+    private static final String PROJECT = "project";
+    private static final String ENDPOINT = "endpoint";
+    private static final String CUSTOM_TAG = "customTag";
+
+    TagService tagService = new TagServiceImpl();
+
+    @Test
+    public void getResourceTags() {
+        Map<String, String> actualResourceTags = tagService.getResourceTags(getUserInfo(), ENDPOINT, PROJECT, CUSTOM_TAG);
+
+        assertEquals("maps of tags are not equals", getExpectedResourceTags(), actualResourceTags);
+    }
+
+    @Test
+    public void getResourceTagsWithNullCustomTag() {
+        Map<String, String> actualResourceTags = tagService.getResourceTags(getUserInfo(), ENDPOINT, PROJECT, null);
+
+        assertEquals("maps of tags are not equals", getExpectedResourceTagsWithNullCustomTag(), actualResourceTags);
+    }
+
+    private Map<String, String> getExpectedResourceTags() {
+        Map<String, String> resourceTags = new HashMap<>();
+        resourceTags.put("user_tag", USER.toLowerCase());
+        resourceTags.put("endpoint_tag", ENDPOINT);
+        resourceTags.put("project_tag", PROJECT);
+        resourceTags.put("custom_tag", CUSTOM_TAG);
+
+        return resourceTags;
+    }
+
+    private Map<String, String> getExpectedResourceTagsWithNullCustomTag() {
+        Map<String, String> resourceTags = new HashMap<>();
+        resourceTags.put("user_tag", USER.toLowerCase());
+        resourceTags.put("endpoint_tag", ENDPOINT);
+        resourceTags.put("project_tag", PROJECT);
+
+        return resourceTags;
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/UserRoleServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/UserRoleServiceImplTest.java
new file mode 100644
index 0000000..97bd463
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/UserRoleServiceImplTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.backendapi.dao.UserRoleDAO;
+import com.epam.datalab.backendapi.resources.TestBase;
+import com.epam.datalab.backendapi.resources.dto.UserRoleDto;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class UserRoleServiceImplTest extends TestBase {
+
+    private static final String ROLE_ID = "roleId";
+    @Mock
+    private UserRoleDAO dao;
+    @InjectMocks
+    private UserRoleServiceImpl userRoleService;
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void createRole() {
+
+        userRoleService.createRole(getUserRole());
+
+        verify(dao).insert(refEq(getUserRole()));
+        verifyNoMoreInteractions(dao);
+    }
+
+    @Test
+    public void updateRole() {
+        when(dao.update(any())).thenReturn(true);
+        userRoleService.updateRole(getUserRole());
+
+        verify(dao).update(refEq(getUserRole()));
+        verifyNoMoreInteractions(dao);
+    }
+
+    @Test
+    public void updateRoleWithException() {
+
+        expectedException.expectMessage("Any of role : [" + ROLE_ID + "] were not found");
+        expectedException.expect(ResourceNotFoundException.class);
+        when(dao.update(any())).thenReturn(false);
+        userRoleService.updateRole(getUserRole());
+    }
+
+    @Test
+    public void removeRole() {
+
+        userRoleService.removeRole(ROLE_ID);
+
+        verify(dao).remove(ROLE_ID);
+        verifyNoMoreInteractions(dao);
+    }
+
+    private UserRoleDto getUserRole() {
+        final UserRoleDto userRoleDto = new UserRoleDto();
+        userRoleDto.setId(ROLE_ID);
+        return userRoleDto;
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/UserSettingServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/UserSettingServiceImplTest.java
new file mode 100644
index 0000000..b7aa811
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/UserSettingServiceImplTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.UserSettingsDAO;
+import com.epam.datalab.backendapi.resources.dto.UserDTO;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.refEq;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class UserSettingServiceImplTest {
+
+    private static final String SETTINGS = "settings";
+    private static final String TOKEN = "Token";
+    private static final String USER = "user";
+    private static final Integer BUDGET = 10;
+    @Mock
+    private UserSettingsDAO settingsDAO;
+    @InjectMocks
+    private UserSettingServiceImpl userSettingService;
+
+    @Test
+    public void saveUISettings() {
+        userSettingService.saveUISettings(getUserInfo(), SETTINGS);
+
+        verify(settingsDAO).setUISettings(refEq(getUserInfo()), eq(SETTINGS));
+        verifyNoMoreInteractions(settingsDAO);
+    }
+
+    @Test
+    public void getUISettings() {
+        when(settingsDAO.getUISettings(any(UserInfo.class))).thenReturn(SETTINGS);
+
+        final String uiSettings = userSettingService.getUISettings(getUserInfo());
+
+        assertEquals(SETTINGS, uiSettings);
+        verify(settingsDAO).getUISettings(refEq(getUserInfo()));
+    }
+
+    @Test
+    public void updateUsersBudget() {
+
+        userSettingService.updateUsersBudget(Collections.singletonList(getBudgetDTO()));
+
+        verify(settingsDAO).updateBudget(refEq(getBudgetDTO()));
+        verifyNoMoreInteractions(settingsDAO);
+    }
+
+    private UserDTO getBudgetDTO() {
+        return new UserDTO(USER, BUDGET, UserDTO.Status.ACTIVE);
+    }
+
+
+    private UserInfo getUserInfo() {
+        return new UserInfo(USER, TOKEN);
+    }
+
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/AccessKeyServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/AccessKeyServiceImplTest.java
new file mode 100644
index 0000000..c92cef0
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/AccessKeyServiceImplTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.resources.TestBase;
+import com.epam.datalab.backendapi.resources.dto.KeysDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AccessKeyServiceImplTest extends TestBase {
+
+    @Mock
+    private SelfServiceApplicationConfiguration conf;
+
+    @InjectMocks
+    private AccessKeyServiceImpl accessKeyService;
+
+
+    @Test
+    public void generateKeys() {
+        UserInfo userInfo = getUserInfo();
+        when(conf.getPrivateKeySize()).thenReturn(2048);
+
+        KeysDTO keysDTO = accessKeyService.generateKeys(userInfo);
+
+        assertEquals("Usernames are not equal", USER.toLowerCase(), keysDTO.getUsername());
+        assertNotNull("Public key is null", keysDTO.getPublicKey());
+        assertNotNull("Private key is null", keysDTO.getPrivateKey());
+    }
+
+    @Test(expected = DatalabException.class)
+    public void generateKeysWithException() {
+        UserInfo userInfo = getUserInfo();
+        when(conf.getPrivateKeySize()).thenReturn(0);
+
+        accessKeyService.generateKeys(userInfo);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/AuditServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/AuditServiceImplTest.java
new file mode 100644
index 0000000..a7ad657
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/AuditServiceImplTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.dao.AuditDAO;
+import com.epam.datalab.backendapi.domain.AuditActionEnum;
+import com.epam.datalab.backendapi.domain.AuditCreateDTO;
+import com.epam.datalab.backendapi.domain.AuditDTO;
+import com.epam.datalab.backendapi.domain.AuditResourceTypeEnum;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.refEq;
+import static org.mockito.Mockito.verify;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AuditServiceImplTest {
+    private static final String USER = "user";
+    private static final String PROJECT = "project";
+    private static final String RESOURCE_NAME = "resourceName";
+    private static final String INFO = "info";
+
+    @Mock
+    private AuditDAO auditDAO;
+    @InjectMocks
+    private AuditServiceImpl auditService;
+
+    @Test
+    public void save() {
+        AuditDTO auditDTO = getAuditDTO();
+
+        auditService.save(auditDTO);
+
+        verify(auditDAO).save(refEq(auditDTO));
+    }
+
+    @Test
+    public void testSave() {
+        AuditCreateDTO auditCreateDTO = getAuditCreateDTO();
+
+        auditService.save(USER, auditCreateDTO);
+
+        verify(auditDAO).save(eq(getAuditDTO(USER, auditCreateDTO)));
+    }
+
+    @Test
+    public void getAudit() {
+        List<String> users = new ArrayList<>();
+        List<String> projects = new ArrayList<>();
+        List<String> resourceNames = new ArrayList<>();
+        List<String> resourceTypes = new ArrayList<>();
+        String dateStart = "";
+        String dateEnd = "";
+        int pageNumber = 1;
+        int pageSize = 10;
+
+        auditService.getAudit(users, projects, resourceNames, resourceTypes, dateStart, dateEnd, pageNumber, pageSize);
+
+        verify(auditDAO).getAudit(refEq(users), refEq(projects), refEq(resourceNames), refEq(resourceTypes), eq(dateStart), eq(dateEnd), eq(pageNumber), eq(pageSize));
+    }
+
+    private AuditDTO getAuditDTO() {
+        return AuditDTO.builder()
+                .user(USER)
+                .project(PROJECT)
+                .build();
+    }
+
+    private AuditDTO getAuditDTO(String user, AuditCreateDTO auditCreateDTO) {
+        return AuditDTO.builder()
+                .user(user)
+                .resourceName(auditCreateDTO.getResourceName())
+                .info(auditCreateDTO.getInfo())
+                .type(auditCreateDTO.getType())
+                .action(AuditActionEnum.FOLLOW_LINK)
+                .build();
+    }
+
+    private AuditCreateDTO getAuditCreateDTO() {
+        return new AuditCreateDTO(RESOURCE_NAME, INFO, AuditResourceTypeEnum.COMPUTE);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BackupServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BackupServiceImplTest.java
new file mode 100644
index 0000000..140b5b6
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BackupServiceImplTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.BackupDAO;
+import com.epam.datalab.backendapi.resources.dto.BackupInfoRecord;
+import com.epam.datalab.dto.backup.EnvBackupDTO;
+import com.epam.datalab.dto.backup.EnvBackupStatus;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.BackupAPI;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class BackupServiceImplTest {
+
+    private final String USER = "test";
+
+    @Mock
+    private RESTService provisioningService;
+    @Mock
+    private BackupDAO backupDao;
+
+    @InjectMocks
+    private BackupServiceImpl backupService;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+
+    @Test
+    public void createBackup() {
+        doNothing().when(backupDao).createOrUpdate(any(EnvBackupDTO.class), anyString(), any(EnvBackupStatus.class));
+        String expectedUuid = "1234-56789765-4321";
+        String token = "token";
+        when(provisioningService.post(refEq(BackupAPI.BACKUP), eq(token), any(EnvBackupDTO.class), any()))
+                .thenReturn(expectedUuid);
+
+        EnvBackupDTO ebDto = EnvBackupDTO.builder().build();
+        UserInfo userInfo = new UserInfo(USER, token);
+        String uuid = backupService.createBackup(ebDto, userInfo);
+        assertNotNull(uuid);
+        assertEquals(expectedUuid, uuid);
+
+        verify(backupDao).createOrUpdate(ebDto, USER, EnvBackupStatus.CREATING);
+        verify(provisioningService).post(BackupAPI.BACKUP, token, ebDto, String.class);
+        verifyNoMoreInteractions(backupDao, provisioningService);
+    }
+
+    @Test
+    public void updateStatus() {
+        doNothing().when(backupDao).createOrUpdate(any(EnvBackupDTO.class), anyString(), any(EnvBackupStatus.class));
+
+        EnvBackupDTO ebDto = EnvBackupDTO.builder().build();
+        backupService.updateStatus(ebDto, USER, EnvBackupStatus.CREATING);
+
+        verify(backupDao).createOrUpdate(ebDto, USER, EnvBackupStatus.CREATING);
+        verifyNoMoreInteractions(backupDao);
+    }
+
+    @Test
+    public void getBackups() {
+        BackupInfoRecord biRecord = mock(BackupInfoRecord.class);
+        when(backupDao.getBackups(anyString())).thenReturn(Collections.singletonList(biRecord));
+
+        List<BackupInfoRecord> biRecords = backupService.getBackups(USER);
+        assertNotNull(biRecords);
+        assertEquals(1, biRecords.size());
+        assertEquals(Collections.singletonList(biRecord), biRecords);
+
+        verify(backupDao).getBackups(USER);
+        verifyNoMoreInteractions(backupDao);
+    }
+
+    @Test
+    public void getBackup() {
+        BackupInfoRecord biRecord = mock(BackupInfoRecord.class);
+        when(backupDao.getBackup(anyString(), anyString())).thenReturn(Optional.of(biRecord));
+
+        String id = "someId";
+        BackupInfoRecord actualBiRecord = backupService.getBackup(USER, id);
+        assertNotNull(actualBiRecord);
+        assertEquals(biRecord, actualBiRecord);
+
+        verify(backupDao).getBackup(USER, id);
+        verifyNoMoreInteractions(backupDao);
+    }
+
+    @Test
+    public void getBackupWithException() {
+        String id = "someId";
+        doThrow(new ResourceNotFoundException(String.format("Backup with id %s was not found for user %s", id, USER)))
+                .when(backupDao).getBackup(USER, id);
+        expectedException.expect(ResourceNotFoundException.class);
+        expectedException.expectMessage("Backup with id " + id + " was not found for user " + USER);
+
+        backupService.getBackup(USER, id);
+    }
+
+    @Test
+    public void getBackupWhenBackupIsAbsent() {
+        String id = "someId";
+        when(backupDao.getBackup(USER, id)).thenReturn(Optional.empty());
+        expectedException.expect(ResourceNotFoundException.class);
+        expectedException.expectMessage("Backup with id " + id + " was not found for user " + USER);
+
+        backupService.getBackup(USER, id);
+    }
+
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BillingServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BillingServiceImplTest.java
new file mode 100644
index 0000000..217e257
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BillingServiceImplTest.java
@@ -0,0 +1,739 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.BillingDAO;
+import com.epam.datalab.backendapi.dao.ImageExploratoryDAO;
+import com.epam.datalab.backendapi.dao.ProjectDAO;
+import com.epam.datalab.backendapi.domain.BillingReport;
+import com.epam.datalab.backendapi.domain.BillingReportLine;
+import com.epam.datalab.backendapi.domain.BudgetDTO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectEndpointDTO;
+import com.epam.datalab.backendapi.resources.TestBase;
+import com.epam.datalab.backendapi.resources.dto.BillingFilter;
+import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.backendapi.resources.dto.QuotaUsageDTO;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.billing.BillingData;
+import com.epam.datalab.dto.billing.BillingResourceType;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import javax.ws.rs.core.GenericType;
+import java.time.LocalDate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.anySet;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class BillingServiceImplTest extends TestBase {
+
+    private static final String PROJECT = "project";
+    private static final String PROJECT_2 = "project2";
+    private static final String ENDPOINT = "endpoint";
+    private static final String USAGE_DATE = "2020-06-00";
+    private static final String USAGE_DATE_FORMATTED = "2020-06";
+    private static final String SERVICE_BASE_NAME = "sbn";
+    private static final String IMAGE_NAME = "image_name";
+    private static final String IMAGE_DESCRIPTION = "imageDescription";
+    private static final String IMAGE_APPLICATION = "image_application";
+    private static final String IMAGE_FULL_NAME = "imageFullName";
+    private static final String BILLING_URL = "http://localhost:8088/api/billing";
+    private static final String EXPLORATORY_NAME = "exploratoryName";
+    private static final String COMPUTE_NAME = "computeName";
+    private static final String COMPUTE_NAME_2 = "computeName2";
+    private static final String CURRENCY = "currency";
+    private static final String PRODUCT = "product";
+    private static final String SHAPE = "shape";
+
+    private static final String SHARED_RESOURCE = "Shared resource";
+    private static final String SSN_ID = SERVICE_BASE_NAME + "-ssn";
+    private static final String SSN_VOLUME_ID = SERVICE_BASE_NAME + "-ssn" + "-volume-primary";
+    private static final String EDGE_ID_1 = SERVICE_BASE_NAME + "-" + PROJECT + "-" + ENDPOINT + "-edge";
+    private static final String EDGE_VOLUME_ID_1 = SERVICE_BASE_NAME + "-" + PROJECT + "-" + ENDPOINT + "-edge-volume-primary";
+    private static final String ENDPOINT_BUCKET_ID = SERVICE_BASE_NAME + "-" + PROJECT + "-" + ENDPOINT + "-bucket";
+    private static final String PROJECT_ENDPOINT_BUCKET_ID_1 = SERVICE_BASE_NAME + "-" + ENDPOINT + "-shared-bucket";
+    private static final String ENDPOINT_ID_1 = SERVICE_BASE_NAME + "-" + ENDPOINT + "-endpoint";
+    private static final String EXPLORATORY_ID = "exploratory_id";
+    private static final String EXPLORATORY_VOLUME_PRIMARY_ID_1 = EXPLORATORY_ID + "-volume-primary";
+    private static final String EXPLORATORY_SECONDARY_ID_1 = EXPLORATORY_ID + "-volume-secondary";
+    private static final String COMPUTE_ID = "compute_id";
+    private static final String COMPUTE_VOLUME_PRIMARY_ID = COMPUTE_ID + "-volume-primary";
+    private static final String COMPUTE_VOLUME_SECONDARY_ID = COMPUTE_ID + "-volume-secondary";
+    private static final String COMPUTE_MASTER_VOLUME_PRIMARY_ID = COMPUTE_ID + "-m" + "-volume-primary";
+    private static final String COMPUTE_MASTER_VOLUME_SECONDARY_ID = COMPUTE_ID + "-m" + "-volume-secondary";
+    private static final String COMPUTE_SLAVE_1_VOLUME_PRIMARY_ID = COMPUTE_ID + "-s1" + "-volume-primary";
+    private static final String COMPUTE_SLAVE_1_VOLUME_SECONDARY_ID = COMPUTE_ID + "-s1" + "-volume-secondary";
+    private static final String COMPUTE_SLAVE_2_VOLUME_PRIMARY_ID = COMPUTE_ID + "-s2" + "-volume-primary";
+    private static final String COMPUTE_SLAVE_2_VOLUME_SECONDARY_ID = COMPUTE_ID + "-s2" + "-volume-secondary";
+    private static final String IMAGE_ID = SERVICE_BASE_NAME + "-" + PROJECT + "-" + ENDPOINT + "-" + IMAGE_APPLICATION + "-" + IMAGE_NAME;
+
+    @Mock
+    private SelfServiceApplicationConfiguration configuration;
+    @Mock
+    private ProjectDAO projectDAO;
+    @Mock
+    private ProjectService projectService;
+    @Mock
+    private BillingDAO billingDAO;
+    @Mock
+    private EndpointService endpointService;
+    @Mock
+    private RESTService provisioningService;
+    @Mock
+    private ExploratoryService exploratoryService;
+    @Mock
+    private ImageExploratoryDAO imageExploratoryDAO;
+
+    @InjectMocks
+    private BillingServiceImpl billingService;
+
+    @Test
+    public void getBillingReport() {
+        when(billingDAO.aggregateBillingData(any(BillingFilter.class))).thenReturn(getBillingReportLineWithCost());
+        when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.FALSE));
+        when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
+        when(exploratoryService.getUserInstance(anyString(), anyString(), anyString())).thenReturn(Optional.of(getUserInstanceDTO()));
+        when(exploratoryService.getUserInstance(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(Optional.of(getUserInstanceDTOWithCompute()));
+
+        BillingReport actualBillingReport = billingService.getBillingReport(getUserInfo(), new BillingFilter());
+
+        assertEquals("reports should be equal", getExpectedBillingReport(), actualBillingReport);
+        verify(billingDAO).aggregateBillingData(new BillingFilter());
+        verify(projectService).get(PROJECT);
+        verify(exploratoryService).getUserInstance(USER, PROJECT, EXPLORATORY_NAME);
+        verify(exploratoryService).getUserInstance(USER, PROJECT, EXPLORATORY_NAME, Boolean.TRUE);
+        verifyNoMoreInteractions(billingDAO);
+    }
+
+    @Test
+    public void getBillingReportWithNullCurrency() {
+        when(billingDAO.aggregateBillingData(any(BillingFilter.class))).thenReturn(getBillingReportLineWithDifferentCurrency());
+        when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
+
+        BillingReport actualBillingReport = billingService.getBillingReport(getUserInfo(), new BillingFilter());
+
+        assertEquals("reports should be equal", getExpectedBillingReportWithNullCurrency(), actualBillingReport);
+        verify(billingDAO).aggregateBillingData(new BillingFilter());
+        verifyNoMoreInteractions(billingDAO);
+    }
+
+    @Test
+    public void downloadReport() {
+        when(billingDAO.aggregateBillingData(any(BillingFilter.class))).thenReturn(getBillingReportLineWithCost());
+        when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.FALSE));
+        when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
+        when(exploratoryService.getUserInstance(anyString(), anyString(), anyString())).thenReturn(Optional.of(getUserInstanceDTO()));
+        when(exploratoryService.getUserInstance(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(Optional.of(getUserInstanceDTOWithCompute()));
+
+        String actualBillingReport = billingService.downloadReport(getUserInfo(), new BillingFilter());
+
+        assertEquals("reports should be equal", getDownloadReport(), actualBillingReport);
+        verify(billingDAO).aggregateBillingData(new BillingFilter());
+        verify(projectService).get(PROJECT);
+        verify(exploratoryService).getUserInstance(USER, PROJECT, EXPLORATORY_NAME);
+        verify(exploratoryService).getUserInstance(USER, PROJECT, EXPLORATORY_NAME, Boolean.TRUE);
+        verifyNoMoreInteractions(billingDAO);
+    }
+
+    @Test
+    public void getExploratoryBillingData() {
+        when(billingDAO.findBillingData(anyString(), anyString(), anyListOf(String.class))).thenReturn(getBillingReportLineWithCost());
+
+        BillingReport actualReport = billingService.getExploratoryBillingData(PROJECT, ENDPOINT, EXPLORATORY_NAME, Arrays.asList(COMPUTE_NAME, COMPUTE_NAME_2));
+
+        assertEquals("reports should be equal", getReport(), actualReport);
+        verify(billingDAO).findBillingData(PROJECT, ENDPOINT, Arrays.asList(COMPUTE_NAME, COMPUTE_NAME_2, EXPLORATORY_NAME));
+        verifyNoMoreInteractions(billingDAO);
+    }
+
+    @Test
+    public void getExploratoryBillingDataWithNullCurrency() {
+        when(billingDAO.findBillingData(anyString(), anyString(), anyListOf(String.class))).thenReturn(getBillingReportLineWithDifferentCurrency());
+
+        BillingReport actualReport = billingService.getExploratoryBillingData(PROJECT, ENDPOINT, EXPLORATORY_NAME, Arrays.asList(COMPUTE_NAME, COMPUTE_NAME_2));
+
+        assertEquals("reports should be equal", getReportWithNullCurrency(), actualReport);
+        verify(billingDAO).findBillingData(PROJECT, ENDPOINT, Arrays.asList(COMPUTE_NAME, COMPUTE_NAME_2, EXPLORATORY_NAME));
+        verifyNoMoreInteractions(billingDAO);
+    }
+
+    @Test
+    public void updateGCPRemoteBillingData() {
+        when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
+        when(configuration.getMaxSparkInstanceCount()).thenReturn(2);
+        when(endpointService.getEndpoints()).thenReturn(getGCPEndpointDTO());
+        when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenReturn(getBillingData());
+        when(projectService.getProjects()).thenReturn(getProjectDTOs());
+        when(exploratoryService.findAll(anySet())).thenReturn(getUserInstanceDTOs());
+        when(imageExploratoryDAO.getImagesForProject(anyString())).thenReturn(getImageInfoRecords());
+
+        billingService.updateRemoteBillingData(getUserInfo());
+
+        verify(endpointService).getEndpoints();
+        verify(provisioningService).get(BILLING_URL, TOKEN, new GenericType<List<BillingData>>() {
+        });
+        verify(projectService).getProjects();
+        verify(exploratoryService).findAll(new HashSet<>(getProjectDTOs()));
+        verify(imageExploratoryDAO).getImagesForProject(PROJECT);
+        verify(billingDAO).deleteByUsageDateRegex(ENDPOINT, USAGE_DATE_FORMATTED);
+        verify(billingDAO).save(getBillingReportLine());
+        verifyNoMoreInteractions(endpointService, provisioningService, billingDAO, projectService, exploratoryService, imageExploratoryDAO);
+    }
+
+    @Test
+    public void updateAWSRemoteBillingData() {
+        when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
+        when(configuration.getMaxSparkInstanceCount()).thenReturn(2);
+        when(endpointService.getEndpoints()).thenReturn(getAWSEndpointDTO());
+        when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenReturn(getBillingData());
+        when(projectService.getProjects()).thenReturn(getProjectDTOs());
+        when(exploratoryService.findAll(anySet())).thenReturn(getUserInstanceDTOs());
+        when(imageExploratoryDAO.getImagesForProject(anyString())).thenReturn(getImageInfoRecords());
+
+        billingService.updateRemoteBillingData(getUserInfo());
+
+        verify(endpointService).getEndpoints();
+        verify(provisioningService).get(BILLING_URL, TOKEN, new GenericType<List<BillingData>>() {
+        });
+        verify(projectService).getProjects();
+        verify(exploratoryService).findAll(new HashSet<>(getProjectDTOs()));
+        verify(imageExploratoryDAO).getImagesForProject(PROJECT);
+        verify(billingDAO).deleteByUsageDate(ENDPOINT, USAGE_DATE);
+        verify(billingDAO).save(getBillingReportLine());
+        verifyNoMoreInteractions(endpointService, provisioningService, billingDAO, projectService, exploratoryService, imageExploratoryDAO);
+    }
+
+    @Test
+    public void updateAzureRemoteBillingData() {
+        when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
+        when(configuration.getMaxSparkInstanceCount()).thenReturn(2);
+        when(endpointService.getEndpoints()).thenReturn(getAzureEndpointDTO());
+        when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenReturn(getBillingData());
+        when(projectService.getProjects()).thenReturn(getProjectDTOs());
+        when(exploratoryService.findAll(anySet())).thenReturn(getUserInstanceDTOs());
+        when(imageExploratoryDAO.getImagesForProject(anyString())).thenReturn(getImageInfoRecords());
+
+        billingService.updateRemoteBillingData(getUserInfo());
+
+        verify(endpointService).getEndpoints();
+        verify(provisioningService).get(BILLING_URL, TOKEN, new GenericType<List<BillingData>>() {
+        });
+        verify(projectService).getProjects();
+        verify(exploratoryService).findAll(new HashSet<>(getProjectDTOs()));
+        verify(imageExploratoryDAO).getImagesForProject(PROJECT);
+        verify(billingDAO).save(getBillingReportLine());
+        verifyNoMoreInteractions(endpointService, provisioningService, billingDAO, projectService, exploratoryService, imageExploratoryDAO);
+    }
+
+    @Test(expected = DatalabException.class)
+    public void updateRemoteBillingDataWithException1() {
+        when(endpointService.getEndpoints()).thenReturn(Collections.emptyList());
+
+        billingService.updateRemoteBillingData(getUserInfo());
+    }
+
+    @Test
+    public void updateRemoteBillingDataWithException2() {
+        when(endpointService.getEndpoints()).thenReturn(getAWSEndpointDTO());
+        when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenThrow(new DatalabException("Exception message"));
+
+        billingService.updateRemoteBillingData(getUserInfo());
+
+        verify(endpointService).getEndpoints();
+        verify(provisioningService).get(BILLING_URL, TOKEN, new GenericType<List<BillingData>>() {
+        });
+        verifyNoMoreInteractions(endpointService, provisioningService, billingDAO, projectService, exploratoryService, imageExploratoryDAO);
+    }
+
+    @Test
+    public void updateRemoteBillingDataWithException3() {
+        when(endpointService.getEndpoints()).thenReturn(getEndpointDTOWithWrongUrl());
+
+        billingService.updateRemoteBillingData(getUserInfo());
+
+        verify(endpointService).getEndpoints();
+        verifyNoMoreInteractions(endpointService, provisioningService, billingDAO, projectService, exploratoryService, imageExploratoryDAO);
+    }
+
+    @Test
+    public void getQuotas() {
+        when(billingDAO.getBillingQuoteUsed()).thenReturn(50);
+        when(projectService.getProjects(any(UserInfo.class))).thenReturn(getProjectDTOs(Boolean.FALSE));
+        when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
+        when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.FALSE));
+        when(billingDAO.getOverallProjectCost(anyString())).thenReturn(5d);
+
+        QuotaUsageDTO quotas = billingService.getQuotas(getUserInfo());
+
+        assertEquals("QuotaUsageDTO should be equal", getQuotaUsageDTO(), quotas);
+        verify(billingDAO).getBillingQuoteUsed();
+        verify(projectService).getProjects(getUserInfo());
+        verify(projectDAO).getAllowedBudget(PROJECT);
+        verify(projectDAO).getAllowedBudget(PROJECT_2);
+        verify(projectService).get(PROJECT);
+        verify(projectService).get(PROJECT_2);
+        verify(billingDAO).getOverallProjectCost(PROJECT);
+        verify(billingDAO).getOverallProjectCost(PROJECT_2);
+        verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
+    }
+
+    @Test
+    public void getMonthlyQuotas() {
+        when(billingDAO.getBillingQuoteUsed()).thenReturn(50);
+        when(projectService.getProjects(any(UserInfo.class))).thenReturn(getProjectDTOs(Boolean.FALSE));
+        when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
+        when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.TRUE));
+        when(billingDAO.getMonthlyProjectCost(anyString(), any(LocalDate.class))).thenReturn(5d);
+
+        QuotaUsageDTO quotas = billingService.getQuotas(getUserInfo());
+
+        assertEquals("QuotaUsageDTO should be equal", getQuotaUsageDTO(), quotas);
+        verify(billingDAO).getBillingQuoteUsed();
+        verify(projectService).getProjects(getUserInfo());
+        verify(projectDAO).getAllowedBudget(PROJECT);
+        verify(projectDAO).getAllowedBudget(PROJECT_2);
+        verify(projectService).get(PROJECT);
+        verify(projectService).get(PROJECT_2);
+        verify(billingDAO).getMonthlyProjectCost(PROJECT, LocalDate.now());
+        verify(billingDAO).getMonthlyProjectCost(PROJECT_2, LocalDate.now());
+        verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
+    }
+
+    @Test
+    public void isProjectQuoteReached() {
+        when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
+        when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.FALSE));
+        when(billingDAO.getOverallProjectCost(anyString())).thenReturn(5d);
+
+        final boolean projectQuoteReached = billingService.isProjectQuoteReached(PROJECT);
+
+        assertEquals("quotes should be equal", Boolean.FALSE, projectQuoteReached);
+        verify(projectDAO).getAllowedBudget(PROJECT);
+        verify(projectService).get(PROJECT);
+        verify(billingDAO).getOverallProjectCost(PROJECT);
+        verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
+    }
+
+    @Test
+    public void isProjectQuoteNullReached() {
+        when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
+        when(projectService.get(anyString())).thenReturn(getProjectQuoteNullDTO());
+        when(billingDAO.getOverallProjectCost(anyString())).thenReturn(5d);
+
+        final boolean projectQuoteReached = billingService.isProjectQuoteReached(PROJECT);
+
+        assertEquals("quotes should be equal", Boolean.FALSE, projectQuoteReached);
+        verify(projectDAO).getAllowedBudget(PROJECT);
+        verify(projectService).get(PROJECT);
+        verify(billingDAO).getOverallProjectCost(PROJECT);
+        verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
+    }
+
+    @Test
+    public void isProjectMonthlyQuoteReached() {
+        when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
+        when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.TRUE));
+        when(billingDAO.getMonthlyProjectCost(anyString(), any(LocalDate.class))).thenReturn(5d);
+
+        final boolean projectQuoteReached = billingService.isProjectQuoteReached(PROJECT);
+
+        assertEquals("quotes should be equal", Boolean.FALSE, projectQuoteReached);
+        verify(projectDAO).getAllowedBudget(PROJECT);
+        verify(projectService).get(PROJECT);
+        verify(billingDAO).getMonthlyProjectCost(PROJECT, LocalDate.now());
+        verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
+    }
+
+    @Test
+    public void getBillingProjectQuoteUsed() {
+        when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
+        when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.FALSE));
+        when(billingDAO.getOverallProjectCost(anyString())).thenReturn(5d);
+
+        final int billingProjectQuoteUsed = billingService.getBillingProjectQuoteUsed(PROJECT);
+
+        assertEquals("quotes should be equal", 50, billingProjectQuoteUsed);
+        verify(projectDAO).getAllowedBudget(PROJECT);
+        verify(projectService).get(PROJECT);
+        verify(billingDAO).getOverallProjectCost(PROJECT);
+        verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
+    }
+
+    @Test
+    public void getBillingProjectQuoteNullUsed() {
+        when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
+        when(projectService.get(anyString())).thenReturn(getProjectQuoteNullDTO());
+        when(billingDAO.getOverallProjectCost(anyString())).thenReturn(5d);
+
+        final int billingProjectQuoteUsed = billingService.getBillingProjectQuoteUsed(PROJECT);
+
+        assertEquals("quotes should be equal", 50, billingProjectQuoteUsed);
+        verify(projectDAO).getAllowedBudget(PROJECT);
+        verify(projectService).get(PROJECT);
+        verify(billingDAO).getOverallProjectCost(PROJECT);
+        verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
+    }
+
+    @Test
+    public void getBillingProjectMonthlyQuoteUsed() {
+        when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
+        when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.TRUE));
+        when(billingDAO.getMonthlyProjectCost(anyString(), any(LocalDate.class))).thenReturn(5d);
+
+        final int billingProjectQuoteUsed = billingService.getBillingProjectQuoteUsed(PROJECT);
+
+        assertEquals("quotes should be equal", 50, billingProjectQuoteUsed);
+        verify(projectDAO).getAllowedBudget(PROJECT);
+        verify(projectService).get(PROJECT);
+        verify(billingDAO).getMonthlyProjectCost(PROJECT, LocalDate.now());
+        verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
+    }
+
+    private ProjectDTO getProjectDTO(boolean isMonthlyBudget) {
+        return ProjectDTO.builder()
+                .name(PROJECT)
+                .budget(new BudgetDTO(10, isMonthlyBudget))
+                .endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT, UserInstanceStatus.RUNNING, null)))
+                .build();
+    }
+
+    private List<ProjectDTO> getProjectDTOs(boolean isMonthlyBudget) {
+        ProjectDTO project1 = ProjectDTO.builder()
+                .name(PROJECT)
+                .budget(new BudgetDTO(10, isMonthlyBudget))
+                .endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT, UserInstanceStatus.RUNNING, null)))
+                .build();
+        ProjectDTO project2 = ProjectDTO.builder()
+                .name(PROJECT_2)
+                .budget(new BudgetDTO(20, isMonthlyBudget))
+                .endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT, UserInstanceStatus.RUNNING, null)))
+                .build();
+        return Arrays.asList(project1, project2);
+    }
+
+    private ProjectDTO getProjectQuoteNullDTO() {
+        return ProjectDTO.builder()
+                .name(PROJECT)
+                .endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT, UserInstanceStatus.RUNNING, null)))
+                .build();
+    }
+
+    private List<ProjectDTO> getProjectDTOs() {
+        return Collections.singletonList(ProjectDTO.builder()
+                .name(PROJECT)
+                .endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT, UserInstanceStatus.RUNNING, null)))
+                .build());
+    }
+
+    private QuotaUsageDTO getQuotaUsageDTO() {
+        Map<String, Integer> projectQuotas = new HashMap<>();
+        projectQuotas.put(PROJECT, 50);
+        projectQuotas.put(PROJECT_2, 50);
+        return QuotaUsageDTO.builder()
+                .totalQuotaUsed(50)
+                .projectQuotas(projectQuotas)
+                .build();
+    }
+
+    private List<BillingData> getBillingData() {
+        BillingData ssnID = BillingData.builder().tag(SSN_ID).usageDate(USAGE_DATE).build();
+        BillingData ssnVolumeID = BillingData.builder().tag(SSN_VOLUME_ID).usageDate(USAGE_DATE).build();
+
+        BillingData edgeID = BillingData.builder().tag(EDGE_ID_1).usageDate(USAGE_DATE).build();
+        BillingData edgeVolumeId = BillingData.builder().tag(EDGE_VOLUME_ID_1).usageDate(USAGE_DATE).build();
+        BillingData endpointBucketId = BillingData.builder().tag(ENDPOINT_BUCKET_ID).usageDate(USAGE_DATE).build();
+
+        BillingData projectEndpointBucketId = BillingData.builder().tag(PROJECT_ENDPOINT_BUCKET_ID_1).usageDate(USAGE_DATE).build();
+        BillingData endpointId = BillingData.builder().tag(ENDPOINT_ID_1).usageDate(USAGE_DATE).build();
+
+        BillingData exploratoryId = BillingData.builder().tag(EXPLORATORY_ID).usageDate(USAGE_DATE).build();
+        BillingData exploratoryPrimaryVolumeId = BillingData.builder().tag(EXPLORATORY_VOLUME_PRIMARY_ID_1).usageDate(USAGE_DATE).build();
+        BillingData exploratorySecondaryVolumeId = BillingData.builder().tag(EXPLORATORY_SECONDARY_ID_1).usageDate(USAGE_DATE).build();
+
+        BillingData computeId = BillingData.builder().tag(COMPUTE_ID).usageDate(USAGE_DATE).build();
+        BillingData computePrimaryVolumeId = BillingData.builder().tag(COMPUTE_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).build();
+        BillingData computeSecondaryVolumeId = BillingData.builder().tag(COMPUTE_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).build();
+        BillingData computeMasterPrimaryVolumeId = BillingData.builder().tag(COMPUTE_MASTER_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).build();
+        BillingData computeMasterSecondaryVolumeId = BillingData.builder().tag(COMPUTE_MASTER_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).build();
+        BillingData computeSlave1PrimaryVolumeId = BillingData.builder().tag(COMPUTE_SLAVE_1_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).build();
+        BillingData computeSlave1SecondaryVolumeId = BillingData.builder().tag(COMPUTE_SLAVE_1_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).build();
+        BillingData computeSlave2PrimaryVolumeId = BillingData.builder().tag(COMPUTE_SLAVE_2_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).build();
+        BillingData computeSlave2SecondaryVolumeId = BillingData.builder().tag(COMPUTE_SLAVE_2_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).build();
+
+        BillingData imageId = BillingData.builder().tag(IMAGE_ID).usageDate(USAGE_DATE).build();
+
+
+        return Arrays.asList(ssnID, ssnVolumeID, edgeID, edgeVolumeId, endpointBucketId, projectEndpointBucketId, endpointId, exploratoryId, exploratoryPrimaryVolumeId,
+                exploratorySecondaryVolumeId, computeId, computePrimaryVolumeId, computeSecondaryVolumeId, computeMasterPrimaryVolumeId, computeMasterSecondaryVolumeId,
+                computeSlave1PrimaryVolumeId, computeSlave1SecondaryVolumeId, computeSlave2PrimaryVolumeId, computeSlave2SecondaryVolumeId, imageId);
+    }
+
+    private List<BillingReportLine> getBillingReportLine() {
+        BillingReportLine ssn = BillingReportLine.builder().datalabId(SSN_ID).usageDate(USAGE_DATE).application(ENDPOINT).resourceName("SSN")
+                .user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceType(BillingResourceType.SSN).build();
+        BillingReportLine ssnVolume = BillingReportLine.builder().datalabId(SSN_VOLUME_ID).usageDate(USAGE_DATE).application(ENDPOINT).resourceName("SSN Volume")
+                .user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceType(BillingResourceType.VOLUME).build();
+
+        BillingReportLine edge = BillingReportLine.builder().datalabId(EDGE_ID_1).usageDate(USAGE_DATE).application(ENDPOINT).resourceName(ENDPOINT)
+                .user(SHARED_RESOURCE).project(PROJECT).resourceType(BillingResourceType.EDGE).build();
+        BillingReportLine edgeVolumeId = BillingReportLine.builder().datalabId(EDGE_VOLUME_ID_1).usageDate(USAGE_DATE).application(ENDPOINT).resourceName("EDGE volume")
+                .user(SHARED_RESOURCE).project(PROJECT).resourceType(BillingResourceType.VOLUME).build();
+        BillingReportLine endpointBucketId = BillingReportLine.builder().datalabId(ENDPOINT_BUCKET_ID).usageDate(USAGE_DATE).application(ENDPOINT).resourceName("Project endpoint shared bucket")
+                .user(SHARED_RESOURCE).project(PROJECT).resourceType(BillingResourceType.BUCKET).build();
+
+        BillingReportLine projectEndpointBucket = BillingReportLine.builder().datalabId(PROJECT_ENDPOINT_BUCKET_ID_1).usageDate(USAGE_DATE).application(ENDPOINT).resourceName("Endpoint shared bucket")
+                .user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceType(BillingResourceType.BUCKET).build();
+        BillingReportLine endpoint = BillingReportLine.builder().datalabId(ENDPOINT_ID_1).usageDate(USAGE_DATE).application(ENDPOINT).resourceName("Endpoint")
+                .user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceType(BillingResourceType.ENDPOINT).build();
+
+        BillingReportLine exploratory = BillingReportLine.builder().datalabId(EXPLORATORY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
+                .user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(EXPLORATORY_NAME).resourceType(BillingResourceType.EXPLORATORY).build();
+        BillingReportLine exploratoryPrimaryVolume = BillingReportLine.builder().datalabId(EXPLORATORY_VOLUME_PRIMARY_ID_1).usageDate(USAGE_DATE).application(ENDPOINT)
+                .user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(EXPLORATORY_NAME).resourceType(BillingResourceType.VOLUME).build();
+        BillingReportLine exploratorySecondaryVolume = BillingReportLine.builder().datalabId(EXPLORATORY_SECONDARY_ID_1).usageDate(USAGE_DATE).application(ENDPOINT)
+                .user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(EXPLORATORY_NAME).resourceType(BillingResourceType.VOLUME).build();
+
+        BillingReportLine compute = BillingReportLine.builder().datalabId(COMPUTE_ID).usageDate(USAGE_DATE).application(ENDPOINT).user(USER).project(PROJECT)
+                .endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.COMPUTATIONAL).shape("3 x " + SHAPE).exploratoryName(EXPLORATORY_NAME).build();
+        BillingReportLine computePrimaryVolume = BillingReportLine.builder().datalabId(COMPUTE_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).application(ENDPOINT).user(USER)
+                .project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
+        BillingReportLine computeSecondaryVolume = BillingReportLine.builder().datalabId(COMPUTE_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).application(ENDPOINT).user(USER)
+                .project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
+        BillingReportLine computeMasterPrimaryVolume = BillingReportLine.builder().datalabId(COMPUTE_MASTER_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
+                .user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
+        BillingReportLine computeMasterSecondaryVolume = BillingReportLine.builder().datalabId(COMPUTE_MASTER_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
+                .user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
+        BillingReportLine computeSlave1PrimaryVolume = BillingReportLine.builder().datalabId(COMPUTE_SLAVE_1_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
+                .user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
+        BillingReportLine computeSlave1SecondaryVolume = BillingReportLine.builder().datalabId(COMPUTE_SLAVE_1_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
+                .user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
+        BillingReportLine computeSlave2PrimaryVolume = BillingReportLine.builder().datalabId(COMPUTE_SLAVE_2_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
+                .user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
+        BillingReportLine computeSlave2SecondaryVolume = BillingReportLine.builder().datalabId(COMPUTE_SLAVE_2_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
+                .user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
+
+        BillingReportLine image = BillingReportLine.builder().datalabId(IMAGE_ID).usageDate(USAGE_DATE).application(ENDPOINT)
+                .user(USER).project(PROJECT).resourceName(IMAGE_NAME).resourceType(BillingResourceType.IMAGE).build();
+
+        return Arrays.asList(ssn, ssnVolume, edge, edgeVolumeId, endpointBucketId, projectEndpointBucket, endpoint, exploratory, exploratoryPrimaryVolume,
+                exploratorySecondaryVolume, compute, computePrimaryVolume, computeSecondaryVolume, computeMasterPrimaryVolume, computeMasterSecondaryVolume,
+                computeSlave1PrimaryVolume, computeSlave1SecondaryVolume, computeSlave2PrimaryVolume, computeSlave2SecondaryVolume, image);
+    }
+
+    private List<BillingReportLine> getBillingReportLineWithCost() {
+        BillingReportLine line1 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-01-01")).usageDateTo(LocalDate.parse("2020-03-01")).cost(1.999)
+                .currency(CURRENCY).datalabId(EDGE_ID_1).user(USER).product(PRODUCT).shape(SHAPE).resourceType(BillingResourceType.EDGE).project(PROJECT)
+                .resourceName(ENDPOINT).build();
+        BillingReportLine line2 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-02-01")).usageDateTo(LocalDate.parse("2020-05-01")).cost(1.0)
+                .currency(CURRENCY).datalabId(EXPLORATORY_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.EXPLORATORY).project(PROJECT)
+                .resourceName(EXPLORATORY_NAME).build();
+        BillingReportLine line3 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-03-01")).usageDateTo(LocalDate.parse("2020-04-01")).cost(1.0)
+                .currency(CURRENCY).datalabId(COMPUTE_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.COMPUTATIONAL).project(PROJECT)
+                .resourceName(COMPUTE_NAME)
+                .exploratoryName(EXPLORATORY_NAME).build();
+
+        return Arrays.asList(line1, line2, line3);
+    }
+
+    private List<BillingReportLine> getBillingReportLineWithDifferentCurrency() {
+        BillingReportLine line1 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-01-01")).usageDateTo(LocalDate.parse("2020-03-01")).cost(1.999)
+                .currency(CURRENCY).build();
+        BillingReportLine line2 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-02-01")).usageDateTo(LocalDate.parse("2020-05-01")).cost(1.0)
+                .currency("currency2").build();
+        BillingReportLine line3 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-03-01")).usageDateTo(LocalDate.parse("2020-04-01")).cost(1.0)
+                .currency(CURRENCY).build();
+
+        return Arrays.asList(line1, line2, line3);
+    }
+
+    private BillingReport getReport() {
+        BillingReportLine line1 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-01-01")).usageDateTo(LocalDate.parse("2020-03-01")).cost(2.0)
+                .currency(CURRENCY).datalabId(EDGE_ID_1).user(USER).product(PRODUCT).shape(SHAPE).resourceType(BillingResourceType.EDGE).project(PROJECT)
+                .resourceName(ENDPOINT).build();
+        BillingReportLine line2 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-02-01")).usageDateTo(LocalDate.parse("2020-05-01")).cost(1.0)
+                .currency(CURRENCY).datalabId(EXPLORATORY_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.EXPLORATORY).project(PROJECT)
+                .resourceName(EXPLORATORY_NAME).build();
+        BillingReportLine line3 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-03-01")).usageDateTo(LocalDate.parse("2020-04-01")).cost(1.0)
+                .currency(CURRENCY).datalabId(COMPUTE_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.COMPUTATIONAL).project(PROJECT)
+                .resourceName(COMPUTE_NAME).exploratoryName(EXPLORATORY_NAME).build();
+        List<BillingReportLine> billingReportLines = Arrays.asList(line1, line2, line3);
+
+        return BillingReport.builder()
+                .name(EXPLORATORY_NAME)
+                .reportLines(billingReportLines)
+                .totalCost(4.0)
+                .currency(CURRENCY)
+                .build();
+    }
+
+    private BillingReport getReportWithNullCurrency() {
+        BillingReportLine line1 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-01-01")).usageDateTo(LocalDate.parse("2020-03-01")).cost(2.0)
+                .currency(CURRENCY).build();
+        BillingReportLine line2 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-02-01")).usageDateTo(LocalDate.parse("2020-05-01")).cost(1.0)
+                .currency("currency2").build();
+        BillingReportLine line3 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-03-01")).usageDateTo(LocalDate.parse("2020-04-01")).cost(1.0)
+                .currency(CURRENCY).build();
+        List<BillingReportLine> billingReportLines = Arrays.asList(line1, line2, line3);
+
+        return BillingReport.builder()
+                .name(EXPLORATORY_NAME)
+                .reportLines(billingReportLines)
+                .totalCost(4.0)
+                .currency(null)
+                .build();
+    }
+
+    private BillingReport getExpectedBillingReport() {
+        BillingReportLine line1 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-01-01")).usageDateTo(LocalDate.parse("2020-03-01")).cost(1.999)
+                .currency(CURRENCY).datalabId(EDGE_ID_1).user(USER).product(PRODUCT).shape(SHAPE).resourceType(BillingResourceType.EDGE).project(PROJECT)
+                .resourceName(ENDPOINT).status(UserInstanceStatus.RUNNING).build();
+        BillingReportLine line2 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-02-01")).usageDateTo(LocalDate.parse("2020-05-01")).cost(1.0)
+                .currency(CURRENCY).datalabId(EXPLORATORY_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.EXPLORATORY).project(PROJECT)
+                .resourceName(EXPLORATORY_NAME).status(UserInstanceStatus.FAILED).build();
+        BillingReportLine line3 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-03-01")).usageDateTo(LocalDate.parse("2020-04-01")).cost(1.0)
+                .currency(CURRENCY).datalabId(COMPUTE_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.COMPUTATIONAL).project(PROJECT)
+                .resourceName(COMPUTE_NAME).exploratoryName(EXPLORATORY_NAME).status(UserInstanceStatus.CREATING).build();
+        List<BillingReportLine> billingReportLines = Arrays.asList(line1, line2, line3);
+
+        return BillingReport.builder()
+                .name("Billing report")
+                .sbn(SERVICE_BASE_NAME)
+                .reportLines(billingReportLines)
+                .usageDateFrom(LocalDate.parse("2020-01-01"))
+                .usageDateTo(LocalDate.parse("2020-05-01"))
+                .totalCost(4.0)
+                .currency(CURRENCY)
+                .isReportHeaderCompletable(Boolean.TRUE)
+                .build();
+    }
+
+    private BillingReport getExpectedBillingReportWithNullCurrency() {
+        return BillingReport.builder()
+                .name("Billing report")
+                .sbn(SERVICE_BASE_NAME)
+                .reportLines(getBillingReportLineWithDifferentCurrency())
+                .usageDateFrom(LocalDate.parse("2020-01-01"))
+                .usageDateTo(LocalDate.parse("2020-05-01"))
+                .totalCost(4.0)
+                .currency(null)
+                .isReportHeaderCompletable(Boolean.TRUE)
+                .build();
+    }
+
+    private String getDownloadReport() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("\"Service base name: ").append(SERVICE_BASE_NAME).append(". Available reporting period from: ").append(LocalDate.parse("2020-01-01"))
+                .append(" to: ").append(LocalDate.parse("2020-05-01")).append("\"\n");
+
+        sb.append(new StringJoiner(",").add("DataLab ID").add("User").add("Project").add("DataLab Resource Type").add("Status").add("Shape").add("Product")
+                .add("Cost\n").toString());
+
+        sb.append(new StringJoiner(",").add(EDGE_ID_1).add(USER).add(PROJECT).add("Edge").add("running").add(SHAPE).add(PRODUCT).add(1.999 + "\n"));
+        sb.append(new StringJoiner(",").add(EXPLORATORY_ID).add(USER).add(PROJECT).add("Exploratory").add("failed").add(SHAPE).add(PRODUCT).add(1.0 + "\n"));
+        sb.append(new StringJoiner(",").add(COMPUTE_ID).add(USER).add(PROJECT).add("Computational").add("creating").add(SHAPE).add(PRODUCT).add(1.0 + "\n"));
+
+        sb.append(",,,,,,,Total: 4.0 currency\n");
+
+        return sb.toString();
+    }
+
+    private List<EndpointDTO> getGCPEndpointDTO() {
+        return Collections.singletonList(new EndpointDTO(ENDPOINT, ENDPOINT_URL, ENDPOINT_ACCOUNT, ENDPOINT_TAG, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.GCP));
+    }
+
+    private List<EndpointDTO> getAWSEndpointDTO() {
+        return Collections.singletonList(new EndpointDTO(ENDPOINT, ENDPOINT_URL, ENDPOINT_ACCOUNT, ENDPOINT_TAG, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS));
+    }
+
+    private List<EndpointDTO> getAzureEndpointDTO() {
+        return Collections.singletonList(new EndpointDTO(ENDPOINT, ENDPOINT_URL, ENDPOINT_ACCOUNT, ENDPOINT_TAG, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AZURE));
+    }
+
+    private List<EndpointDTO> getEndpointDTOWithWrongUrl() {
+        return Collections.singletonList(new EndpointDTO(ENDPOINT, "wrong url", ENDPOINT_ACCOUNT, ENDPOINT_TAG, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AZURE));
+    }
+
+    private List<UserInstanceDTO> getUserInstanceDTOs() {
+        return Collections.singletonList(
+                new UserInstanceDTO().withExploratoryId(EXPLORATORY_ID).withUser(USER).withProject(PROJECT).withExploratoryName(EXPLORATORY_NAME).withEndpoint(ENDPOINT)
+                        .withResources(Collections.singletonList(getCompute())));
+    }
+
+    private UserInstanceDTO getUserInstanceDTO() {
+        return new UserInstanceDTO().withExploratoryId(EXPLORATORY_ID).withUser(USER).withProject(PROJECT).withExploratoryName(EXPLORATORY_NAME).withEndpoint(ENDPOINT)
+                .withStatus("failed");
+    }
+
+    private UserInstanceDTO getUserInstanceDTOWithCompute() {
+        return new UserInstanceDTO().withExploratoryId(EXPLORATORY_ID).withUser(USER).withProject(PROJECT).withExploratoryName(EXPLORATORY_NAME).withEndpoint(ENDPOINT)
+                .withStatus("failed").withResources(Collections.singletonList(getCompute()));
+    }
+
+    private UserComputationalResource getCompute() {
+        UserComputationalResource resource = new UserComputationalResource();
+        resource.setComputationalId(COMPUTE_ID);
+        resource.setComputationalName(COMPUTE_NAME);
+        resource.setImageName(DataEngineType.SPARK_STANDALONE.getName());
+        resource.setDataengineInstanceCount(3);
+        resource.setDataengineShape(SHAPE);
+        resource.setStatus("creating");
+
+        return resource;
+    }
+
+    private List<ImageInfoRecord> getImageInfoRecords() {
+        return Collections.singletonList(
+                new ImageInfoRecord(IMAGE_NAME, IMAGE_DESCRIPTION, PROJECT, ENDPOINT, USER, IMAGE_APPLICATION, IMAGE_FULL_NAME, ImageStatus.CREATED)
+        );
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BucketServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BucketServiceImplTest.java
new file mode 100644
index 0000000..bb4f0e2
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BucketServiceImplTest.java
@@ -0,0 +1,262 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.resources.TestBase;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.dto.bucket.BucketDTO;
+import com.epam.datalab.dto.bucket.BucketDeleteDTO;
+import com.epam.datalab.dto.bucket.FolderUploadDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import org.apache.http.HttpStatus;
+import org.glassfish.jersey.media.multipart.FormDataMultiPart;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.Response;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class BucketServiceImplTest extends TestBase {
+    private static final String BUCKET_GET_OBJECTS = "%sbucket/%s";
+    private static final String BUCKET_UPLOAD_OBJECT = "%sbucket/upload";
+    private static final String BUCKET_UPLOAD_FOLDER = "%sbucket/folder/upload";
+    private static final String BUCKET_DOWNLOAD_OBJECT = "%sbucket/%s/object/%s/download";
+    private static final String BUCKET_DELETE_OBJECT = "%sbucket/objects/delete";
+    private static final String BUCKET = "bucket";
+    private static final String OBJECT = "object";
+    private static final String SIZE = "size";
+    private static final String DATE = "date";
+    private static final String FOLDER = "folder/";
+
+    @Mock
+    private EndpointService endpointService;
+    @Mock
+    private RESTService provisioningService;
+    @InjectMocks
+    private BucketServiceImpl bucketService;
+
+    @Test
+    public void getObjects() {
+        EndpointDTO endpointDTO = getEndpointDTO();
+        List<BucketDTO> objects = getBucketList();
+        when(endpointService.get(anyString())).thenReturn(endpointDTO);
+        when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenReturn(objects);
+
+        List<BucketDTO> actualObjects = bucketService.getObjects(getUserInfo(), BUCKET, ENDPOINT_NAME);
+
+        assertEquals("lists should be equal", objects, actualObjects);
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).get(String.format(BUCKET_GET_OBJECTS, ENDPOINT_URL, BUCKET), TOKEN, new GenericType<List<BucketDTO>>() {
+        });
+        verifyNoMoreInteractions(endpointService, provisioningService);
+    }
+
+    @Test(expected = DatalabException.class)
+    public void getObjectsWithException() {
+        EndpointDTO endpointDTO = getEndpointDTO();
+        when(endpointService.get(anyString())).thenReturn(endpointDTO);
+        when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenThrow(new DatalabException("Exception message"));
+
+        bucketService.getObjects(getUserInfo(), BUCKET, ENDPOINT_NAME);
+
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).get(String.format(BUCKET_GET_OBJECTS, ENDPOINT_URL, BUCKET), TOKEN, new GenericType<List<BucketDTO>>() {
+        });
+
+        verifyNoMoreInteractions(endpointService, provisioningService);
+    }
+
+    @Test
+    public void uploadObject() {
+        EndpointDTO endpointDTO = getEndpointDTO();
+        Response response = Response.ok().build();
+        when(endpointService.get(anyString())).thenReturn(endpointDTO);
+        when(provisioningService.postForm(anyString(), anyString(), any(FormDataMultiPart.class), any())).thenReturn(response);
+
+        bucketService.uploadObject(getUserInfo(), BUCKET, OBJECT, ENDPOINT_NAME, getInputStream(), APPLICATION_JSON, 0, null);
+
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).postForm(eq(String.format(BUCKET_UPLOAD_OBJECT, ENDPOINT_URL)), eq(TOKEN), any(FormDataMultiPart.class), eq(Response.class));
+        verifyNoMoreInteractions(endpointService, provisioningService);
+    }
+
+    @Test(expected = DatalabException.class)
+    public void uploadObjectWithException1() {
+        EndpointDTO endpointDTO = getEndpointDTO();
+        Response response = Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).build();
+        when(endpointService.get(anyString())).thenReturn(endpointDTO);
+        when(provisioningService.postForm(anyString(), anyString(), any(FormDataMultiPart.class), any())).thenReturn(response);
+
+        bucketService.uploadObject(getUserInfo(), BUCKET, OBJECT, ENDPOINT_NAME, getInputStream(), APPLICATION_JSON, 0, null);
+
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).postForm(eq(String.format(BUCKET_UPLOAD_OBJECT, ENDPOINT_URL)), eq(TOKEN), any(FormDataMultiPart.class), eq(Response.class));
+        verifyNoMoreInteractions(endpointService, provisioningService);
+    }
+
+    @Test(expected = DatalabException.class)
+    public void uploadObjectWithException2() {
+        EndpointDTO endpointDTO = getEndpointDTO();
+        when(endpointService.get(anyString())).thenReturn(endpointDTO);
+
+        bucketService.uploadObject(getUserInfo(), BUCKET, OBJECT, ENDPOINT_NAME, null, APPLICATION_JSON, 0, null);
+
+        verify(endpointService).get(ENDPOINT_NAME);
+        verifyNoMoreInteractions(endpointService, provisioningService);
+    }
+
+    @Test
+    public void uploadFolder() {
+        EndpointDTO endpointDTO = getEndpointDTO();
+        Response response = Response.ok().build();
+        when(endpointService.get(anyString())).thenReturn(endpointDTO);
+        when(provisioningService.post(anyString(), anyString(), any(FolderUploadDTO.class), any())).thenReturn(response);
+
+        bucketService.uploadFolder(getUserInfo(), BUCKET, FOLDER, ENDPOINT_NAME, null);
+
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).post(eq(String.format(BUCKET_UPLOAD_FOLDER, ENDPOINT_URL)), eq(TOKEN), eq(getFolderUploadDTO()), eq(Response.class));
+        verifyNoMoreInteractions(endpointService, provisioningService);
+    }
+
+    @Test(expected = DatalabException.class)
+    public void uploadFolderWithException1() {
+        EndpointDTO endpointDTO = getEndpointDTO();
+        Response response = Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).build();
+        when(endpointService.get(anyString())).thenReturn(endpointDTO);
+        when(provisioningService.post(anyString(), anyString(), any(FolderUploadDTO.class), any())).thenReturn(response);
+
+        bucketService.uploadFolder(getUserInfo(), BUCKET, FOLDER, ENDPOINT_NAME, null);
+
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).post(eq(String.format(BUCKET_UPLOAD_FOLDER, ENDPOINT_URL)), eq(TOKEN), eq(getFolderUploadDTO()), eq(Response.class));
+        verifyNoMoreInteractions(endpointService, provisioningService);
+    }
+
+    @Test(expected = DatalabException.class)
+    public void uploadFolderWithException2() {
+        bucketService.uploadFolder(getUserInfo(), BUCKET, "folder_name_without_slash", ENDPOINT_NAME, null);
+    }
+
+    @Test
+    public void downloadObject() throws IOException {
+        EndpointDTO endpointDTO = getEndpointDTO();
+        HttpServletResponse response = mock(HttpServletResponse.class);
+        ServletOutputStream outputStream = mock(ServletOutputStream.class);
+        when(endpointService.get(anyString())).thenReturn(endpointDTO);
+        when(provisioningService.getWithMediaTypes(anyString(), anyString(), any(), anyString(), anyString())).thenReturn(getInputStream());
+        when(response.getOutputStream()).thenReturn(outputStream);
+
+        bucketService.downloadObject(getUserInfo(), BUCKET, OBJECT, ENDPOINT_NAME, response, null);
+
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).getWithMediaTypes(eq(String.format(BUCKET_DOWNLOAD_OBJECT, ENDPOINT_URL, BUCKET, OBJECT)), eq(TOKEN), eq(InputStream.class),
+                eq(APPLICATION_JSON), eq(APPLICATION_OCTET_STREAM));
+        verifyNoMoreInteractions(endpointService, provisioningService);
+    }
+
+    @Test(expected = DatalabException.class)
+    public void downloadObjectWithException() {
+        EndpointDTO endpointDTO = getEndpointDTO();
+        HttpServletResponse response = mock(HttpServletResponse.class);
+        when(endpointService.get(anyString())).thenReturn(endpointDTO);
+        when(provisioningService.getWithMediaTypes(anyString(), anyString(), any(), anyString(), anyString())).thenThrow(new DatalabException("Exception message"));
+
+        bucketService.downloadObject(getUserInfo(), BUCKET, OBJECT, ENDPOINT_NAME, response, null);
+
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).getWithMediaTypes(eq(String.format(BUCKET_DOWNLOAD_OBJECT, ENDPOINT_URL, BUCKET, OBJECT)), eq(TOKEN), eq(InputStream.class),
+                eq(APPLICATION_JSON), eq(APPLICATION_OCTET_STREAM));
+        verifyNoMoreInteractions(endpointService, provisioningService);
+    }
+
+    @Test
+    public void deleteObjects() {
+        EndpointDTO endpointDTO = getEndpointDTO();
+        Response response = Response.ok().build();
+        when(endpointService.get(anyString())).thenReturn(endpointDTO);
+        when(provisioningService.post(anyString(), anyString(), any(BucketDeleteDTO.class), any())).thenReturn(response);
+
+        bucketService.deleteObjects(getUserInfo(), BUCKET, Collections.singletonList(OBJECT), ENDPOINT_NAME, null);
+
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).post(eq(String.format(BUCKET_DELETE_OBJECT, ENDPOINT_URL)), eq(TOKEN), eq(getBucketDeleteDTO()), eq(Response.class));
+        verifyNoMoreInteractions(endpointService, provisioningService);
+    }
+
+    @Test(expected = DatalabException.class)
+    public void deleteObjectsWithException() {
+        EndpointDTO endpointDTO = getEndpointDTO();
+        Response response = Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).build();
+        when(endpointService.get(anyString())).thenReturn(endpointDTO);
+        when(provisioningService.post(anyString(), anyString(), any(BucketDeleteDTO.class), any())).thenReturn(response);
+
+        bucketService.deleteObjects(getUserInfo(), BUCKET, Collections.singletonList(OBJECT), ENDPOINT_NAME, null);
+
+        verify(endpointService).get(ENDPOINT_NAME);
+        verify(provisioningService).post(eq(String.format(BUCKET_DELETE_OBJECT, ENDPOINT_URL)), eq(TOKEN), eq(getBucketDeleteDTO()), eq(Response.class));
+        verifyNoMoreInteractions(endpointService, provisioningService);
+    }
+
+    private List<BucketDTO> getBucketList() {
+        return Collections.singletonList(BucketDTO.builder()
+                .bucket(BUCKET)
+                .object(OBJECT)
+                .size(SIZE)
+                .lastModifiedDate(DATE)
+                .build());
+    }
+
+    private FolderUploadDTO getFolderUploadDTO() {
+        return new FolderUploadDTO(BUCKET, FOLDER);
+    }
+
+    private BucketDeleteDTO getBucketDeleteDTO() {
+        return new BucketDeleteDTO(BUCKET, Collections.singletonList(OBJECT));
+    }
+
+    private ByteArrayInputStream getInputStream() {
+        return new ByteArrayInputStream("input stream".getBytes());
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ComputationalServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ComputationalServiceImplTest.java
new file mode 100644
index 0000000..0452841
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ComputationalServiceImplTest.java
@@ -0,0 +1,784 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.ComputationalDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectEndpointDTO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.resources.dto.ComputationalCreateFormDTO;
+import com.epam.datalab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.service.TagService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import com.epam.datalab.dto.computational.ComputationalClusterConfigDTO;
+import com.epam.datalab.dto.computational.ComputationalStartDTO;
+import com.epam.datalab.dto.computational.ComputationalStatusDTO;
+import com.epam.datalab.dto.computational.ComputationalStopDTO;
+import com.epam.datalab.dto.computational.ComputationalTerminateDTO;
+import com.epam.datalab.dto.computational.SparkStandaloneClusterResource;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.rest.client.RESTService;
+import com.epam.datalab.rest.contracts.ComputationalAPI;
+import com.mongodb.client.result.UpdateResult;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import static com.epam.datalab.dto.UserInstanceStatus.CREATING;
+import static com.epam.datalab.dto.UserInstanceStatus.RUNNING;
+import static com.epam.datalab.dto.UserInstanceStatus.STOPPED;
+import static com.epam.datalab.rest.contracts.ComputationalAPI.AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE;
+import static com.epam.datalab.rest.contracts.ComputationalAPI.AUDIT_MESSAGE;
+import static java.util.Collections.singletonList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyListOf;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+
+@RunWith(MockitoJUnitRunner.class)
+public class ComputationalServiceImplTest {
+
+    private static final long MAX_INACTIVITY = 10L;
+    private static final String DOCKER_DATALAB_DATAENGINE = "docker.datalab-dataengine";
+    private static final String DOCKER_DATALAB_DATAENGINE_SERVICE = "docker.datalab-dataengine-service";
+    private static final String COMP_ID = "compId";
+    private final String USER = "test";
+    private final String TOKEN = "token";
+    private final String EXPLORATORY_NAME = "expName";
+    private final String PROJECT = "project";
+    private final String COMP_NAME = "compName";
+    private final String NOTE_BOOK_NAME = "notebookName";
+    private final String UUID = "1234-56789765-4321";
+    private final LocalDateTime LAST_ACTIVITY = LocalDateTime.now().minusMinutes(MAX_INACTIVITY);
+
+    private UserInfo userInfo;
+    private List<ComputationalCreateFormDTO> formList;
+    private UserInstanceDTO userInstance;
+    private ComputationalStatusDTO computationalStatusDTOWithStatusTerminating;
+    private ComputationalStatusDTO computationalStatusDTOWithStatusFailed;
+    private ComputationalStatusDTO computationalStatusDTOWithStatusStopping;
+    private ComputationalStatusDTO computationalStatusDTOWithStatusStarting;
+    private SparkStandaloneClusterResource sparkClusterResource;
+    private UserComputationalResource ucResource;
+
+    @Mock
+    private ProjectService projectService;
+    @Mock
+    private ExploratoryDAO exploratoryDAO;
+    @Mock
+    private ComputationalDAO computationalDAO;
+    @Mock
+    private RESTService provisioningService;
+    @Mock
+    private SelfServiceApplicationConfiguration configuration;
+    @Mock
+    private RequestBuilder requestBuilder;
+    @Mock
+    private RequestId requestId;
+    @Mock
+    private TagService tagService;
+    @Mock
+    private EndpointService endpointService;
+
+    @InjectMocks
+    private ComputationalServiceImpl computationalService;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Before
+    public void setUp() {
+        userInfo = getUserInfo();
+        userInstance = getUserInstanceDto();
+        formList = getFormList();
+        computationalStatusDTOWithStatusTerminating = getComputationalStatusDTOWithStatus("terminating");
+        computationalStatusDTOWithStatusFailed = getComputationalStatusDTOWithStatus("failed");
+        computationalStatusDTOWithStatusStopping = getComputationalStatusDTOWithStatus("stopping");
+        computationalStatusDTOWithStatusStarting = getComputationalStatusDTOWithStatus("starting");
+        sparkClusterResource = getSparkClusterResource();
+        ucResource = getUserComputationalResource(STOPPED, DOCKER_DATALAB_DATAENGINE);
+    }
+
+    @Test
+    public void createSparkCluster() {
+        ProjectDTO projectDTO = getProjectDTO();
+        when(projectService.get(anyString())).thenReturn(projectDTO);
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(computationalDAO.addComputational(anyString(), anyString(), anyString(),
+                any(SparkStandaloneClusterResource.class))).thenReturn(true);
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+
+        ComputationalBase compBaseMocked = mock(ComputationalBase.class);
+        when(requestBuilder.newComputationalCreate(any(UserInfo.class), any(ProjectDTO.class),
+                any(UserInstanceDTO.class), any(SparkStandaloneClusterCreateForm.class), any(EndpointDTO.class)))
+                .thenReturn(compBaseMocked);
+        when(provisioningService.post(anyString(), anyString(), any(ComputationalBase.class), any())).thenReturn(UUID);
+        when(requestId.put(anyString(), anyString())).thenReturn(UUID);
+
+        SparkStandaloneClusterCreateForm form = (SparkStandaloneClusterCreateForm) formList.get(0);
+        boolean creationResult = computationalService.createSparkCluster(userInfo, form.getName(), form, PROJECT,
+                String.format(AUDIT_MESSAGE, form.getNotebookName()));
+        assertTrue(creationResult);
+
+        verify(projectService).get(PROJECT);
+        verify(computationalDAO).addComputational(eq(USER), eq(EXPLORATORY_NAME), eq(PROJECT), refEq(sparkClusterResource));
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(requestBuilder).newComputationalCreate(
+                refEq(userInfo), refEq(projectDTO), refEq(userInstance), refEq(form), refEq(endpointDTO()));
+
+        verify(provisioningService)
+                .post(endpointDTO().getUrl() + ComputationalAPI.COMPUTATIONAL_CREATE_SPARK, TOKEN, compBaseMocked,
+                        String.class);
+
+        verify(requestId).put(USER, UUID);
+        verifyNoMoreInteractions(projectService, configuration, computationalDAO, requestBuilder, provisioningService, requestId);
+    }
+
+    @Test
+    public void createSparkClusterWhenResourceAlreadyExists() {
+        when(computationalDAO.addComputational(anyString(), anyString(), anyString(),
+                any(SparkStandaloneClusterResource.class))).thenReturn(false);
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+
+        SparkStandaloneClusterCreateForm form = (SparkStandaloneClusterCreateForm) formList.get(0);
+        boolean creationResult = computationalService.createSparkCluster(userInfo, form.getName(), form, PROJECT,
+                String.format(AUDIT_MESSAGE, form.getNotebookName()));
+        assertFalse(creationResult);
+        verify(computationalDAO).addComputational(eq(USER), eq(EXPLORATORY_NAME), eq(PROJECT), refEq(sparkClusterResource));
+        verifyNoMoreInteractions(configuration, computationalDAO);
+    }
+
+    @Test
+    public void createSparkClusterWhenMethodFetchExploratoryFieldsThrowsException() {
+        when(computationalDAO.addComputational(anyString(), anyString(), anyString(),
+                any(SparkStandaloneClusterResource.class))).thenReturn(true);
+        doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
+                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
+
+        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+
+        SparkStandaloneClusterCreateForm form = (SparkStandaloneClusterCreateForm) formList.get(0);
+        try {
+            computationalService.createSparkCluster(userInfo, form.getName(), form, PROJECT, String.format(AUDIT_MESSAGE, form.getNotebookName()));
+        } catch (ResourceNotFoundException e) {
+            assertEquals("Exploratory for user with name not found", e.getMessage());
+        }
+
+        verify(computationalDAO, never()).addComputational(USER, EXPLORATORY_NAME, PROJECT, sparkClusterResource);
+        verify(computationalDAO, never()).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed,
+                "self"));
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(configuration, computationalDAO, exploratoryDAO);
+    }
+
+    @Test
+    public void createSparkClusterWhenMethodNewComputationalCreateThrowsException() {
+        ProjectDTO projectDTO = getProjectDTO();
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(projectService.get(anyString())).thenReturn(projectDTO);
+        when(computationalDAO.addComputational(anyString(), anyString(), anyString(),
+                any(SparkStandaloneClusterResource.class))).thenReturn(true);
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+
+        doThrow(new DatalabException("Cannot create instance of resource class "))
+                .when(requestBuilder).newComputationalCreate(any(UserInfo.class), any(ProjectDTO.class),
+                any(UserInstanceDTO.class), any(SparkStandaloneClusterCreateForm.class), any(EndpointDTO.class));
+
+        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+
+        SparkStandaloneClusterCreateForm form = (SparkStandaloneClusterCreateForm) formList.get(0);
+        try {
+            computationalService.createSparkCluster(userInfo, form.getName(), form, PROJECT, String.format(AUDIT_MESSAGE, form.getNotebookName()));
+        } catch (DatalabException e) {
+            assertEquals("Cannot create instance of resource class ", e.getMessage());
+        }
+        verify(projectService).get(PROJECT);
+        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, form, endpointDTO());
+        verifyNoMoreInteractions(projectService, configuration, computationalDAO, exploratoryDAO, requestBuilder);
+    }
+
+    @Test
+    public void terminateComputationalEnvironment() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+        String explId = "explId";
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+
+        String compId = "compId";
+        UserComputationalResource ucResource = new UserComputationalResource();
+        ucResource.setComputationalName(COMP_NAME);
+        ucResource.setImageName("dataengine-service");
+        ucResource.setComputationalId(compId);
+        when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString())).thenReturn(ucResource);
+
+        ComputationalTerminateDTO ctDto = new ComputationalTerminateDTO();
+        ctDto.setComputationalName(COMP_NAME);
+        ctDto.setExploratoryName(EXPLORATORY_NAME);
+        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, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, AUDIT_MESSAGE);
+
+        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating, "self"));
+        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
+
+        verify(requestBuilder).newComputationalTerminate(userInfo.getName(), userInstance, ucResource, endpointDTO());
+
+        verify(provisioningService).post(endpointDTO().getUrl() + ComputationalAPI.COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC, TOKEN, ctDto,
+                String.class);
+
+        verify(requestId).put(USER, UUID);
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(computationalDAO, exploratoryDAO, requestBuilder, provisioningService, requestId);
+    }
+
+    @Test
+    public void terminateComputationalEnvironmentWhenMethodUpdateComputationalStatusThrowsException() {
+        doThrow(new DatalabException("Could not update computational resource status"))
+                .when(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating,
+                "self"));
+
+        when(computationalDAO.updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self")))
+                .thenReturn(mock(UpdateResult.class));
+
+        try {
+            computationalService.terminateComputational(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, AUDIT_MESSAGE);
+        } catch (DatalabException e) {
+            assertEquals("Could not update computational resource status", e.getMessage());
+        }
+
+        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating, "self"));
+        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
+        verifyNoMoreInteractions(computationalDAO);
+    }
+
+    @Test
+    public void terminateComputationalEnvironmentWhenMethodFetchComputationalFieldsThrowsException() {
+        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+
+        doThrow(new DatalabException("Computational resource for user with exploratory name not found."))
+                .when(computationalDAO).fetchComputationalFields(anyString(), anyString(), anyString(), anyString());
+        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+
+        try {
+            computationalService.terminateComputational(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, AUDIT_MESSAGE);
+        } catch (DatalabException e) {
+            assertEquals("Computational resource for user with exploratory name not found.", e.getMessage());
+        }
+
+        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating, "self"));
+        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
+        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(computationalDAO, exploratoryDAO);
+    }
+
+    @Test
+    public void terminateComputationalEnvironmentWhenMethodNewComputationalTerminateThrowsException() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+
+        String compId = "compId";
+        UserComputationalResource ucResource = new UserComputationalResource();
+        ucResource.setComputationalName(COMP_NAME);
+        ucResource.setImageName("dataengine-service");
+        ucResource.setComputationalId(compId);
+        when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString())).thenReturn(ucResource);
+
+        doThrow(new DatalabException("Cannot create instance of resource 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, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, AUDIT_MESSAGE);
+        } catch (DatalabException e) {
+            assertEquals("Cannot create instance of resource class ", e.getMessage());
+        }
+
+        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating, "self"));
+        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+
+        verify(requestBuilder).newComputationalTerminate(userInfo.getName(), userInstance, ucResource, endpointDTO());
+        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
+        verifyNoMoreInteractions(computationalDAO, exploratoryDAO, requestBuilder);
+    }
+
+    @Test
+    public void createDataEngineService() {
+        ProjectDTO projectDTO = getProjectDTO();
+        when(projectService.get(anyString())).thenReturn(projectDTO);
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(computationalDAO.addComputational(anyString(), anyString(), anyString(), any(UserComputationalResource.class)))
+                .thenReturn(true);
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+
+        ComputationalBase compBaseMocked = mock(ComputationalBase.class);
+        when(requestBuilder.newComputationalCreate(any(UserInfo.class), any(ProjectDTO.class),
+                any(UserInstanceDTO.class), any(ComputationalCreateFormDTO.class), any(EndpointDTO.class)))
+                .thenReturn(compBaseMocked);
+
+        when(provisioningService.post(anyString(), anyString(), any(ComputationalBase.class), any())).thenReturn(UUID);
+        when(requestId.put(anyString(), anyString())).thenReturn(UUID);
+
+        ComputationalCreateFormDTO form = formList.get(1);
+        boolean creationResult = computationalService.createDataEngineService(userInfo, form.getName(), form, ucResource, PROJECT,
+                String.format(AUDIT_MESSAGE, form.getNotebookName()));
+        assertTrue(creationResult);
+
+        verify(projectService).get(PROJECT);
+
+        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), any(ComputationalCreateFormDTO.class), refEq(endpointDTO()));
+
+        verify(provisioningService)
+                .post(endpointDTO().getUrl() + ComputationalAPI.COMPUTATIONAL_CREATE_CLOUD_SPECIFIC, TOKEN,
+                        compBaseMocked, String.class);
+
+        verify(requestId).put(USER, UUID);
+        verifyNoMoreInteractions(projectService, computationalDAO, exploratoryDAO, requestBuilder, provisioningService, requestId);
+    }
+
+    @Test
+    public void createDataEngineServiceWhenComputationalResourceNotAdded() {
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        when(computationalDAO.addComputational(anyString(), anyString(), any(), any(UserComputationalResource.class)))
+                .thenReturn(false);
+
+        ComputationalCreateFormDTO form = formList.get(1);
+        boolean creationResult = computationalService.createDataEngineService(userInfo, form.getName(), form, ucResource, PROJECT,
+                String.format(AUDIT_MESSAGE, form.getNotebookName()));
+        assertFalse(creationResult);
+
+        verify(computationalDAO).addComputational(eq(USER), eq(EXPLORATORY_NAME), eq(PROJECT), refEq(ucResource));
+        verifyNoMoreInteractions(computationalDAO);
+    }
+
+    @Test
+    public void createDataEngineServiceWhenMethodFetchExploratoryFieldsThrowsException() {
+        when(computationalDAO.addComputational(anyString(), anyString(), anyString(), any(UserComputationalResource.class)))
+                .thenReturn(true);
+        doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
+                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
+
+        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+
+        ComputationalCreateFormDTO form = formList.get(1);
+        try {
+            computationalService.createDataEngineService(userInfo, form.getName(), form, ucResource, PROJECT,
+                    String.format(AUDIT_MESSAGE, form.getNotebookName()));
+        } catch (DatalabException e) {
+            assertEquals("Exploratory for user with name not found", e.getMessage());
+        }
+
+        verify(computationalDAO, never())
+                .addComputational(eq(USER), eq(EXPLORATORY_NAME), eq(PROJECT), refEq(ucResource));
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+
+        verify(computationalDAO, never()).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed,
+                "self"));
+        verifyNoMoreInteractions(computationalDAO, exploratoryDAO);
+    }
+
+    @Test
+    public void createDataEngineServiceWhenMethodNewComputationalCreateThrowsException() {
+        ProjectDTO projectDTO = getProjectDTO();
+        when(projectService.get(anyString())).thenReturn(projectDTO);
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(computationalDAO.addComputational(anyString(), anyString(), any(), any(UserComputationalResource.class)))
+                .thenReturn(true);
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+
+        doThrow(new DatalabException("Cannot create instance of resource class "))
+                .when(requestBuilder).newComputationalCreate(any(UserInfo.class), any(ProjectDTO.class),
+                any(UserInstanceDTO.class), any(ComputationalCreateFormDTO.class), any(EndpointDTO.class));
+
+        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+
+        ComputationalCreateFormDTO form = formList.get(1);
+        try {
+            computationalService.createDataEngineService(userInfo, form.getName(), form, ucResource, PROJECT,
+                    String.format(AUDIT_MESSAGE, form.getNotebookName()));
+        } catch (DatalabException e) {
+            assertEquals("Could not send request for creation the computational resource compName: " +
+                    "Cannot create instance of resource class ", e.getMessage());
+        }
+
+        verify(projectService).get(PROJECT);
+        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(form), refEq(endpointDTO()));
+        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
+
+        verifyNoMoreInteractions(projectService, computationalDAO, exploratoryDAO, requestBuilder);
+    }
+
+    @Test
+    public void stopSparkCluster() {
+        final UserInstanceDTO exploratory = getUserInstanceDto();
+        exploratory.setResources(singletonList(getUserComputationalResource(RUNNING, DOCKER_DATALAB_DATAENGINE)));
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(exploratory);
+        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+
+        ComputationalStopDTO computationalStopDTO = new ComputationalStopDTO();
+        when(requestBuilder.newComputationalStop(anyString(), any(UserInstanceDTO.class), anyString(),
+                any(EndpointDTO.class))).thenReturn(computationalStopDTO);
+        when(provisioningService.post(anyString(), anyString(), any(ComputationalBase.class), any()))
+                .thenReturn("someUuid");
+        when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
+
+        computationalService.stopSparkCluster(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, String.format(AUDIT_MESSAGE, EXPLORATORY_NAME));
+
+        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusStopping, "self"));
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, true);
+        verify(requestBuilder).newComputationalStop(eq(userInfo.getName()), refEq(exploratory), eq(COMP_NAME), refEq(endpointDTO()));
+        verify(provisioningService)
+                .post(eq(endpointDTO().getUrl() + "computational/stop/spark"), eq(TOKEN), refEq(computationalStopDTO),
+                        eq(String.class));
+        verify(requestId).put(USER, "someUuid");
+        verifyNoMoreInteractions(computationalDAO, exploratoryDAO, requestBuilder,
+                provisioningService, requestId);
+    }
+
+    @Test
+    public void stopSparkClusterWhenDataengineTypeIsAnother() {
+        final UserInstanceDTO exploratory = getUserInstanceDto();
+        exploratory.setResources(singletonList(getUserComputationalResource(RUNNING, DOCKER_DATALAB_DATAENGINE_SERVICE)));
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(exploratory);
+        expectedException.expect(IllegalStateException.class);
+        expectedException.expectMessage("There is no running dataengine compName for exploratory expName");
+
+        computationalService.stopSparkCluster(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, String.format(AUDIT_MESSAGE, EXPLORATORY_NAME));
+    }
+
+    @Test
+    public void startSparkCluster() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        final UserInstanceDTO exploratory = getUserInstanceDto();
+        exploratory.setResources(singletonList(getUserComputationalResource(STOPPED, DOCKER_DATALAB_DATAENGINE)));
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(exploratory);
+        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+
+        ComputationalStartDTO computationalStartDTO = new ComputationalStartDTO();
+        when(requestBuilder.newComputationalStart(any(UserInfo.class), any(UserInstanceDTO.class), anyString(),
+                any(EndpointDTO.class))).thenReturn(computationalStartDTO);
+        when(provisioningService.post(anyString(), anyString(), any(ComputationalBase.class), any()))
+                .thenReturn("someUuid");
+        when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
+
+        computationalService.startSparkCluster(userInfo, EXPLORATORY_NAME, COMP_NAME, PROJECT, String.format(AUDIT_MESSAGE, EXPLORATORY_NAME));
+
+        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusStarting, "self"));
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, true);
+        verify(requestBuilder).newComputationalStart(refEq(userInfo), refEq(exploratory), eq(COMP_NAME), refEq(endpointDTO()));
+        verify(provisioningService)
+                .post(eq(endpointDTO().getUrl() + "computational/start/spark"), eq(TOKEN),
+                        refEq(computationalStartDTO),
+                        eq(String.class));
+        verify(requestId).put(USER, "someUuid");
+        verifyNoMoreInteractions(computationalDAO, exploratoryDAO, requestBuilder,
+                provisioningService, requestId);
+    }
+
+    @Test
+    public void startSparkClusterWhenDataengineStatusIsRunning() {
+        final UserInstanceDTO userInstanceDto = getUserInstanceDto();
+        userInstanceDto.setResources(singletonList(getUserComputationalResource(RUNNING,
+                DOCKER_DATALAB_DATAENGINE_SERVICE)));
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(userInstanceDto);
+
+        expectedException.expect(IllegalStateException.class);
+        expectedException.expectMessage("There is no stopped dataengine compName for exploratory expName");
+
+        computationalService.startSparkCluster(userInfo, EXPLORATORY_NAME, COMP_NAME, PROJECT, String.format(AUDIT_MESSAGE, EXPLORATORY_NAME));
+    }
+
+    @Test
+    public void getComputationalResource() {
+        when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString())).thenReturn(ucResource);
+
+        Optional<UserComputationalResource> expectedResource = Optional.of(ucResource);
+        Optional<UserComputationalResource> actualResource =
+                computationalService.getComputationalResource(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
+        assertEquals(expectedResource, actualResource);
+
+        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
+        verifyNoMoreInteractions(computationalDAO);
+    }
+
+    @Test
+    public void getComputationalResourceWithException() {
+        doThrow(new DatalabException("Computational resource not found"))
+                .when(computationalDAO).fetchComputationalFields(anyString(), anyString(), anyString(), anyString());
+
+        Optional<UserComputationalResource> expectedResource = Optional.empty();
+        Optional<UserComputationalResource> actualResource =
+                computationalService.getComputationalResource(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
+        assertEquals(expectedResource, actualResource);
+
+        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
+        verifyNoMoreInteractions(computationalDAO);
+    }
+
+    @Test
+    public void testUpdateSparkClusterConfig() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        final ComputationalClusterConfigDTO clusterConfigDTO = new ComputationalClusterConfigDTO();
+        final UserInstanceDTO userInstanceDto = getUserInstanceDto();
+        final List<ClusterConfig> config = Collections.singletonList(new ClusterConfig());
+        userInstanceDto.setResources(Collections.singletonList(getUserComputationalResource(RUNNING, COMP_NAME)));
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(userInstanceDto);
+        when(requestBuilder.newClusterConfigUpdate(any(UserInfo.class), any(UserInstanceDTO.class),
+                any(UserComputationalResource.class), anyListOf(ClusterConfig.class), any(EndpointDTO.class)))
+                .thenReturn(clusterConfigDTO);
+        when(provisioningService.post(anyString(), anyString(), any(ComputationalClusterConfigDTO.class), any()))
+                .thenReturn("someUuid");
+        computationalService.updateSparkClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME,
+                COMP_NAME, config, String.format(AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE, COMP_NAME, NOTE_BOOK_NAME));
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, true);
+        verify(requestBuilder).newClusterConfigUpdate(refEq(getUserInfo()), refEq(userInstanceDto),
+                refEq(getUserComputationalResource(RUNNING, COMP_NAME)),
+                eq(Collections.singletonList(new ClusterConfig())), eq(endpointDTO()));
+        verify(requestId).put(USER, "someUuid");
+        verify(computationalDAO).updateComputationalFields(refEq(new ComputationalStatusDTO()
+                .withProject(PROJECT)
+                .withConfig(config)
+                .withUser(USER)
+                .withExploratoryName(EXPLORATORY_NAME)
+                .withComputationalName(COMP_NAME)
+                .withStatus(UserInstanceStatus.RECONFIGURING.toString()), "self"));
+        verify(provisioningService).post(eq(endpointDTO().getUrl() + "computational/spark/reconfigure"),
+                eq(getUserInfo().getAccessToken()),
+                refEq(new ComputationalClusterConfigDTO()), eq(String.class));
+
+    }
+
+    @Test
+    public void testUpdateSparkClusterConfigWhenClusterIsNotRunning() {
+        final UserInstanceDTO userInstanceDto = getUserInstanceDto();
+        final List<ClusterConfig> config = Collections.singletonList(new ClusterConfig());
+        userInstanceDto.setResources(Collections.singletonList(getUserComputationalResource(STOPPED, COMP_NAME)));
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(userInstanceDto);
+        try {
+            computationalService.updateSparkClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME,
+                    COMP_NAME, config, String.format(AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE, COMP_NAME, NOTE_BOOK_NAME));
+        } catch (ResourceNotFoundException e) {
+            assertEquals("Running computational resource with name compName for exploratory expName not found", e.getMessage());
+        }
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, true);
+        verifyNoMoreInteractions(exploratoryDAO);
+        verifyZeroInteractions(provisioningService, requestBuilder, requestId);
+
+    }
+
+    @Test
+    public void testUpdateSparkClusterConfigWhenClusterIsNotFound() {
+        final UserInstanceDTO userInstanceDto = getUserInstanceDto();
+        final List<ClusterConfig> config = Collections.singletonList(new ClusterConfig());
+        userInstanceDto.setResources(Collections.singletonList(getUserComputationalResource(STOPPED, COMP_NAME)));
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(userInstanceDto);
+        try {
+            computationalService.updateSparkClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME,
+                    COMP_NAME + "X", config, String.format(AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE, COMP_NAME, NOTE_BOOK_NAME));
+        } catch (ResourceNotFoundException e) {
+            assertEquals("Running computational resource with name compNameX for exploratory expName not found",
+                    e.getMessage());
+        }
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, true);
+        verifyNoMoreInteractions(exploratoryDAO);
+        verifyZeroInteractions(provisioningService, requestBuilder, requestId);
+
+    }
+
+    @Test
+    public void testGetClusterConfig() {
+        when(computationalDAO.getClusterConfig(anyString(), anyString(), anyString(), anyString())).thenReturn(Collections.singletonList(getClusterConfig()));
+
+        final List<ClusterConfig> clusterConfig = computationalService.getClusterConfig(getUserInfo(), PROJECT,
+                EXPLORATORY_NAME, COMP_NAME);
+        final ClusterConfig config = clusterConfig.get(0);
+
+        assertEquals(1, clusterConfig.size());
+        assertEquals("test", config.getClassification());
+        assertNull(config.getConfigurations());
+        assertNull(config.getProperties());
+    }
+
+
+    @Test
+    public void testGetClusterConfigWithException() {
+        when(computationalDAO.getClusterConfig(anyString(), anyString(), anyString(), anyString())).thenThrow(new RuntimeException(
+                "Exception"));
+
+        expectedException.expectMessage("Exception");
+        expectedException.expect(RuntimeException.class);
+        computationalService.getClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME, COMP_NAME);
+    }
+
+    private ClusterConfig getClusterConfig() {
+        final ClusterConfig config = new ClusterConfig();
+        config.setClassification("test");
+        return config;
+    }
+
+    private UserInfo getUserInfo() {
+        return new UserInfo(USER, TOKEN);
+    }
+
+    private UserInstanceDTO getUserInstanceDto() {
+        return new UserInstanceDTO().withUser(USER).withExploratoryName(EXPLORATORY_NAME)
+                .withExploratoryId("explId")
+                .withProject(PROJECT)
+                .withTags(Collections.emptyMap());
+    }
+
+    private List<ComputationalCreateFormDTO> getFormList() {
+        SparkStandaloneClusterCreateForm sparkClusterForm = new SparkStandaloneClusterCreateForm();
+        sparkClusterForm.setNotebookName(EXPLORATORY_NAME);
+        sparkClusterForm.setName(COMP_NAME);
+        sparkClusterForm.setProject(PROJECT);
+        sparkClusterForm.setDataEngineInstanceCount(String.valueOf(2));
+        sparkClusterForm.setImage("dataengine");
+        ComputationalCreateFormDTO desClusterForm = new ComputationalCreateFormDTO();
+        desClusterForm.setNotebookName(EXPLORATORY_NAME);
+        desClusterForm.setName(COMP_NAME);
+
+        return Arrays.asList(sparkClusterForm, desClusterForm);
+    }
+
+    private ComputationalStatusDTO getComputationalStatusDTOWithStatus(String status) {
+        return new ComputationalStatusDTO()
+                .withUser(USER)
+                .withProject(PROJECT)
+                .withExploratoryName(EXPLORATORY_NAME)
+                .withComputationalName(COMP_NAME)
+                .withStatus(UserInstanceStatus.of(status));
+    }
+
+    private SparkStandaloneClusterResource getSparkClusterResource() {
+        return SparkStandaloneClusterResource.builder()
+                .computationalName(COMP_NAME)
+                .imageName("dataengine")
+                .status(CREATING.toString())
+                .dataEngineInstanceCount(String.valueOf(2))
+                .tags(Collections.emptyMap())
+                .build();
+    }
+
+    private EndpointDTO endpointDTO() {
+        return new EndpointDTO("test", "url", "", null, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
+    }
+
+
+    private UserComputationalResource getUserComputationalResource(UserInstanceStatus status, String imageName) {
+        UserComputationalResource ucResource = new UserComputationalResource();
+        ucResource.setComputationalName(COMP_NAME);
+        ucResource.setImageName("dataengine");
+        ucResource.setImageName(imageName);
+        ucResource.setStatus(status.toString());
+        ucResource.setLastActivity(LAST_ACTIVITY);
+        ucResource.setComputationalId(COMP_ID);
+        ucResource.setTags(Collections.emptyMap());
+        final SchedulerJobDTO schedulerData = new SchedulerJobDTO();
+        schedulerData.setCheckInactivityRequired(true);
+        schedulerData.setMaxInactivity(MAX_INACTIVITY);
+        ucResource.setSchedulerData(schedulerData);
+        return ucResource;
+    }
+
+    private ProjectDTO getProjectDTO() {
+        return new ProjectDTO(PROJECT, Collections.emptySet(), "", "", null,
+                singletonList(new ProjectEndpointDTO("endpoint", UserInstanceStatus.RUNNING,
+                        new EdgeInfo())), true);
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/EndpointServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/EndpointServiceImplTest.java
new file mode 100644
index 0000000..5b978b7
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/EndpointServiceImplTest.java
@@ -0,0 +1,310 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.dao.EndpointDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.UserRoleDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.EndpointResourcesDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectEndpointDTO;
+import com.epam.datalab.backendapi.resources.TestBase;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceConflictException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.rest.client.RESTService;
+import org.apache.http.HttpStatus;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import javax.ws.rs.core.Response;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class EndpointServiceImplTest extends TestBase {
+    private static final String HEALTH_CHECK = "healthcheck";
+    private static final String EXPLORATORY_NAME_1 = "expName1";
+    private static final String EXPLORATORY_NAME_2 = "expName2";
+    private static final String PROJECT_NAME_1 = "projectName";
+    private static final String PROJECT_NAME_2 = "projectName_2";
+
+    @Mock
+    private EndpointDAO endpointDAO;
+    @Mock
+    private ProjectService projectService;
+    @Mock
+    private ExploratoryDAO exploratoryDAO;
+    @Mock
+    private RESTService provisioningService;
+    @Mock
+    private UserRoleDAO userRoleDao;
+
+    @InjectMocks
+    private EndpointServiceImpl endpointService;
+
+    @Test
+    public void getEndpoints() {
+        List<EndpointDTO> endpoints = getEndpointDTOs();
+        when(endpointDAO.getEndpoints()).thenReturn(endpoints);
+
+        List<EndpointDTO> actualEndpoints = endpointService.getEndpoints();
+
+        assertEquals("lists should be equal", endpoints, actualEndpoints);
+        verify(endpointDAO).getEndpoints();
+        verifyNoMoreInteractions(endpointDAO);
+    }
+
+    @Test
+    public void getEndpointsWithStatus() {
+        List<EndpointDTO> endpoints = Collections.singletonList(getEndpointDTO());
+        when(endpointDAO.getEndpointsWithStatus(anyString())).thenReturn(endpoints);
+
+        List<EndpointDTO> actualEndpoints = endpointService.getEndpointsWithStatus(EndpointDTO.EndpointStatus.ACTIVE);
+
+        assertEquals("lists should be equal", endpoints, actualEndpoints);
+        verify(endpointDAO).getEndpointsWithStatus(EndpointDTO.EndpointStatus.ACTIVE.toString());
+        verifyNoMoreInteractions(endpointDAO);
+    }
+
+    @Test
+    public void getEndpointResources() {
+        List<UserInstanceDTO> userInstances = getUserInstances();
+        List<ProjectDTO> projectDTOs = getProjectDTOs();
+        when(exploratoryDAO.fetchExploratoriesByEndpointWhereStatusNotIn(anyString(), anyListOf(UserInstanceStatus.class)))
+                .thenReturn(userInstances);
+        when(projectService.getProjectsByEndpoint(anyString())).thenReturn(projectDTOs);
+
+        EndpointResourcesDTO actualEndpointResources = endpointService.getEndpointResources(ENDPOINT_NAME);
+
+        assertEquals("objects should be equal", new EndpointResourcesDTO(userInstances, projectDTOs), actualEndpointResources);
+        verify(exploratoryDAO).fetchExploratoriesByEndpointWhereStatusNotIn(ENDPOINT_NAME, Arrays.asList(UserInstanceStatus.TERMINATED, UserInstanceStatus.FAILED));
+        verify(projectService).getProjectsByEndpoint(ENDPOINT_NAME);
+        verifyNoMoreInteractions(exploratoryDAO, projectService);
+    }
+
+    @Test
+    public void get() {
+        EndpointDTO endpointDTO = getEndpointDTO();
+        when(endpointDAO.get(anyString())).thenReturn(Optional.of(endpointDTO));
+
+        EndpointDTO actualEndpointDTO = endpointService.get(ENDPOINT_NAME);
+
+        assertEquals("objects should be equal", endpointDTO, actualEndpointDTO);
+        verify(endpointDAO).get(ENDPOINT_NAME);
+        verifyNoMoreInteractions(endpointDAO);
+    }
+
+    @Test(expected = ResourceNotFoundException.class)
+    public void getWithException() {
+        when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
+
+        endpointService.get(ENDPOINT_NAME);
+    }
+
+    @Test
+    public void create() {
+        Response response = mock(Response.class);
+        when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
+        when(endpointDAO.getEndpointWithUrl(anyString())).thenReturn(Optional.empty());
+        when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(response);
+        when(response.readEntity(any(Class.class))).thenReturn(CloudProvider.AWS);
+        when(response.getStatus()).thenReturn(HttpStatus.SC_OK);
+
+        endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
+
+        verify(endpointDAO).get(ENDPOINT_NAME);
+        verify(endpointDAO).getEndpointWithUrl(ENDPOINT_URL);
+        verify(provisioningService).get(ENDPOINT_URL + HEALTH_CHECK, TOKEN, Response.class);
+        verify(endpointDAO).create(getEndpointDTO());
+        verify(userRoleDao).updateMissingRoles(CloudProvider.AWS);
+        verifyNoMoreInteractions(endpointDAO, provisioningService, userRoleDao);
+    }
+
+    @Test(expected = ResourceConflictException.class)
+    public void createWithException1() {
+        when(endpointDAO.get(anyString())).thenReturn(Optional.of(getEndpointDTO()));
+
+        endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
+    }
+
+    @Test(expected = ResourceConflictException.class)
+    public void createWithException2() {
+        when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
+        when(endpointDAO.getEndpointWithUrl(anyString())).thenReturn(Optional.of(getEndpointDTO()));
+
+        endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
+    }
+
+    @Test(expected = DatalabException.class)
+    public void createWithException3() {
+        when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
+        when(endpointDAO.getEndpointWithUrl(anyString())).thenReturn(Optional.empty());
+        when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenThrow(new DatalabException("Exception message"));
+
+        endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
+    }
+
+    @Test(expected = DatalabException.class)
+    public void createWithException4() {
+        Response response = mock(Response.class);
+        when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
+        when(endpointDAO.getEndpointWithUrl(anyString())).thenReturn(Optional.empty());
+        when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(response);
+        when(response.readEntity(any(Class.class))).thenReturn(new Object());
+
+        endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
+    }
+
+    @Test(expected = ResourceNotFoundException.class)
+    public void createWithException5() {
+        Response response = mock(Response.class);
+        when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
+        when(endpointDAO.getEndpointWithUrl(anyString())).thenReturn(Optional.empty());
+        when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(response);
+        when(response.readEntity(any(Class.class))).thenReturn(CloudProvider.AWS);
+        when(response.getStatus()).thenReturn(HttpStatus.SC_INTERNAL_SERVER_ERROR);
+
+        endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
+    }
+
+    @Test(expected = DatalabException.class)
+    public void createWithException6() {
+        Response response = mock(Response.class);
+        when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
+        when(endpointDAO.getEndpointWithUrl(anyString())).thenReturn(Optional.empty());
+        when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(response);
+        when(response.readEntity(any(Class.class))).thenReturn(null);
+        when(response.getStatus()).thenReturn(HttpStatus.SC_OK);
+
+        endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
+    }
+
+    @Test
+    public void updateEndpointStatus() {
+        endpointService.updateEndpointStatus(ENDPOINT_NAME, EndpointDTO.EndpointStatus.ACTIVE);
+
+        verify(endpointDAO).updateEndpointStatus(ENDPOINT_NAME, EndpointDTO.EndpointStatus.ACTIVE.toString());
+        verifyNoMoreInteractions(endpointDAO);
+    }
+
+    @Test
+    public void remove() {
+        List<ProjectDTO> projectDTOs = getProjectDTOs();
+        List<EndpointDTO> endpointDTOs = getEndpointDTOs();
+        when(endpointDAO.get(anyString())).thenReturn(Optional.of(getEndpointDTO()));
+        when(projectService.getProjectsByEndpoint(anyString())).thenReturn(projectDTOs);
+        when(projectService.checkExploratoriesAndComputationalProgress(anyString(), anyListOf(String.class))).thenReturn(Boolean.TRUE);
+        when(endpointDAO.getEndpoints()).thenReturn(endpointDTOs);
+
+        endpointService.remove(getUserInfo(), ENDPOINT_NAME);
+
+        verify(endpointDAO).get(ENDPOINT_NAME);
+        verify(projectService).getProjectsByEndpoint(ENDPOINT_NAME);
+        verify(projectService).checkExploratoriesAndComputationalProgress(PROJECT_NAME_1, Collections.singletonList(ENDPOINT_NAME));
+        verify(projectService).checkExploratoriesAndComputationalProgress(PROJECT_NAME_2, Collections.singletonList(ENDPOINT_NAME));
+        verify(projectService).terminateEndpoint(getUserInfo(), ENDPOINT_NAME, PROJECT_NAME_1);
+        verify(projectService).terminateEndpoint(getUserInfo(), ENDPOINT_NAME, PROJECT_NAME_2);
+        verify(endpointDAO).remove(ENDPOINT_NAME);
+        verify(endpointDAO).getEndpoints();
+        verify(userRoleDao).removeUnnecessaryRoles(CloudProvider.AWS, Arrays.asList(CloudProvider.AWS, CloudProvider.GCP));
+        verifyNoMoreInteractions(endpointDAO, projectService, userRoleDao);
+    }
+
+    @Test(expected = ResourceNotFoundException.class)
+    public void removeWithException1() {
+        when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
+
+        endpointService.remove(getUserInfo(), ENDPOINT_NAME);
+    }
+
+    @Test(expected = ResourceConflictException.class)
+    public void removeWithException2() {
+        when(endpointDAO.get(anyString())).thenReturn(Optional.of(getEndpointDTO()));
+        when(projectService.getProjectsByEndpoint(anyString())).thenReturn(getProjectDTOs());
+        when(projectService.checkExploratoriesAndComputationalProgress(anyString(), anyListOf(String.class))).thenReturn(Boolean.FALSE);
+
+        endpointService.remove(getUserInfo(), ENDPOINT_NAME);
+    }
+
+    @Test(expected = ResourceConflictException.class)
+    public void removeWithException3() {
+        when(endpointDAO.get(anyString())).thenReturn(Optional.of(getEndpointDTO()));
+        when(projectService.getProjectsByEndpoint(anyString())).thenReturn(getCreatingProjectDTO());
+        when(projectService.checkExploratoriesAndComputationalProgress(anyString(), anyListOf(String.class))).thenReturn(Boolean.TRUE);
+
+        endpointService.remove(getUserInfo(), ENDPOINT_NAME);
+    }
+
+    private List<UserInstanceDTO> getUserInstances() {
+        return Arrays.asList(
+                new UserInstanceDTO().withExploratoryName(EXPLORATORY_NAME_1).withUser(USER).withProject(PROJECT_NAME_1).withEndpoint(ENDPOINT_NAME),
+                new UserInstanceDTO().withExploratoryName(EXPLORATORY_NAME_2).withUser(USER).withProject(PROJECT_NAME_1).withEndpoint(ENDPOINT_NAME)
+        );
+    }
+
+    private List<EndpointDTO> getEndpointDTOs() {
+        return Arrays.asList(getEndpointDTO(), getInactiveEndpointDTO());
+    }
+
+    private EndpointDTO getInactiveEndpointDTO() {
+        return new EndpointDTO("local2", "endpoint_url2", "endpoint_account2", "endpoint_tag2",
+                EndpointDTO.EndpointStatus.INACTIVE, CloudProvider.GCP);
+    }
+
+    private List<ProjectDTO> getProjectDTOs() {
+        ProjectDTO project1 = ProjectDTO.builder()
+                .name(PROJECT_NAME_1)
+                .endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, null)))
+                .build();
+        ProjectDTO project2 = ProjectDTO.builder()
+                .name(PROJECT_NAME_2)
+                .endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, null)))
+                .build();
+        return Arrays.asList(project1, project2);
+    }
+
+    private List<ProjectDTO> getCreatingProjectDTO() {
+        ProjectDTO project = ProjectDTO.builder()
+                .name(PROJECT_NAME_1)
+                .endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.CREATING, null)))
+                .build();
+        return Collections.singletonList(project);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImplTest.java
new file mode 100644
index 0000000..8127874
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImplTest.java
@@ -0,0 +1,369 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.EnvDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.UserSettingsDAO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectEndpointDTO;
+import com.epam.datalab.backendapi.resources.dto.UserDTO;
+import com.epam.datalab.backendapi.resources.dto.UserResourceInfo;
+import com.epam.datalab.backendapi.service.ComputationalService;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceConflictException;
+import com.epam.datalab.model.ResourceEnum;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import static com.epam.datalab.dto.UserInstanceStatus.CREATING;
+import static com.epam.datalab.dto.UserInstanceStatus.CREATING_IMAGE;
+import static com.epam.datalab.dto.UserInstanceStatus.STARTING;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anySet;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+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 DATALAB_SYSTEM_USER = "DataLab system user";
+    private static final String DATALAB_SYSTEM_USER_TOKEN = "token";
+    private static final String USER = "test";
+    private static final String EXPLORATORY_NAME_1 = "expName1";
+    private static final String EXPLORATORY_NAME_2 = "expName2";
+    private static final String TOKEN = "token";
+    private static final String UUID = "213-12312-321";
+    private static final String PROJECT_NAME = "projectName";
+    private static final String ENDPOINT_NAME = "endpointName";
+    private static final String SHAPE = "shape";
+
+    @Mock
+    private EnvDAO envDAO;
+    @Mock
+    private ExploratoryDAO exploratoryDAO;
+    @Mock
+    private SecurityService securityService;
+    @Mock
+    private ExploratoryService exploratoryService;
+    @Mock
+    private ComputationalService computationalService;
+    @Mock
+    private UserSettingsDAO userSettingsDAO;
+    @Mock
+    private ProjectService projectService;
+
+    @InjectMocks
+    private EnvironmentServiceImpl environmentService;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void getActiveUsers() {
+        doReturn(Collections.singleton(USER)).when(envDAO).fetchActiveEnvUsers();
+        doReturn(Collections.singleton(USER + "2")).when(envDAO).fetchUsersNotIn(anySet());
+        when(userSettingsDAO.getAllowedBudget(anyString())).thenReturn(Optional.empty());
+        final List<UserDTO> activeUsers = environmentService.getUsers();
+
+        assertEquals(2, activeUsers.size());
+        assertEquals(USER, activeUsers.get(0).getName());
+        assertEquals(USER + "2", activeUsers.get(1).getName());
+
+        verify(userSettingsDAO).getAllowedBudget(USER);
+        verify(userSettingsDAO).getAllowedBudget(USER + "2");
+        verify(envDAO).fetchActiveEnvUsers();
+        verify(envDAO).fetchUsersNotIn(Collections.singleton(USER));
+        verifyNoMoreInteractions(envDAO);
+    }
+
+    @Test
+    public void getAllEnv() {
+        when(exploratoryDAO.getInstances()).thenReturn(getUserInstances());
+        when(projectService.getProjects(any(UserInfo.class))).thenReturn(Collections.singletonList(getProjectDTO()));
+
+        List<UserResourceInfo> actualAllEnv = environmentService.getAllEnv(getUserInfo());
+
+        List<UserResourceInfo> userResources = Arrays.asList(getUserResourceInfoEdge(), getUserResourceInfo(EXPLORATORY_NAME_1), getUserResourceInfo(EXPLORATORY_NAME_2));
+        assertEquals("lists are not equal", userResources, actualAllEnv);
+        verify(exploratoryDAO).getInstances();
+        verify(projectService).getProjects(getUserInfo());
+        verifyNoMoreInteractions(exploratoryDAO, projectService);
+    }
+
+    @Test
+    public void getAllEnvWithoutEdge() {
+        when(exploratoryDAO.getInstances()).thenReturn(getUserInstances());
+        when(projectService.getProjects(any(UserInfo.class))).thenReturn(Collections.singletonList(getProjectDTOWithoutEndpoint()));
+
+        List<UserResourceInfo> actualAllEnv = environmentService.getAllEnv(getUserInfo());
+
+        List<UserResourceInfo> userResources = Arrays.asList(getUserResourceInfo(EXPLORATORY_NAME_1), getUserResourceInfo(EXPLORATORY_NAME_2));
+        assertEquals("lists are not equal", userResources, actualAllEnv);
+        verify(exploratoryDAO).getInstances();
+        verify(projectService).getProjects(getUserInfo());
+        verifyNoMoreInteractions(exploratoryDAO, projectService);
+    }
+
+    @Test
+    public void stopAll() {
+        when(projectService.getProjects()).thenReturn(Collections.singletonList(getProjectDTO()));
+        when(exploratoryDAO.fetchProjectExploratoriesWhereStatusIn(anyString(), anyListOf(UserInstanceStatus.class))).thenReturn(Collections.emptyList());
+        when(exploratoryDAO.fetchRunningExploratoryFieldsForProject(anyString())).thenReturn(getUserInstances());
+        when(securityService.getServiceAccountInfo(anyString())).thenReturn(getDataLabSystemUser());
+        when(projectService.get(anyString())).thenReturn(getProjectDTO());
+
+        environmentService.stopAll();
+
+        verify(projectService).getProjects();
+        verify(exploratoryDAO).fetchProjectExploratoriesWhereStatusIn(PROJECT_NAME, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE);
+        verify(exploratoryDAO).fetchRunningExploratoryFieldsForProject(PROJECT_NAME);
+        verify(securityService, times(3)).getServiceAccountInfo(DATALAB_SYSTEM_USER);
+        verify(exploratoryService).stop(getDataLabSystemUser(), USER, PROJECT_NAME, EXPLORATORY_NAME_1, AUDIT_QUOTA_MESSAGE);
+        verify(exploratoryService).stop(getDataLabSystemUser(), USER, PROJECT_NAME, EXPLORATORY_NAME_2, AUDIT_QUOTA_MESSAGE);
+        verify(projectService).get(PROJECT_NAME);
+        verify(projectService).stop(getDataLabSystemUser(), ENDPOINT_NAME, PROJECT_NAME, AUDIT_QUOTA_MESSAGE);
+        verifyNoMoreInteractions(projectService, exploratoryDAO, securityService, exploratoryService);
+    }
+
+    @Test(expected = ResourceConflictException.class)
+    public void stopAllWithException() {
+        when(projectService.getProjects()).thenReturn(Collections.singletonList(getProjectDTO()));
+        when(exploratoryDAO.fetchProjectExploratoriesWhereStatusIn(PROJECT_NAME, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE)).thenReturn(getUserInstances());
+
+        environmentService.stopAll();
+
+        verify(projectService).getProjects();
+        verify(exploratoryDAO).fetchProjectExploratoriesWhereStatusIn(PROJECT_NAME, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE);
+        verifyNoMoreInteractions(projectService, exploratoryDAO, securityService, exploratoryService);
+    }
+
+    @Test
+    public void stopAllWithStoppedProject() {
+        when(projectService.getProjects()).thenReturn(Collections.singletonList(getProjectDTOWithStoppedEdge()));
+        when(exploratoryDAO.fetchProjectExploratoriesWhereStatusIn(anyString(), anyListOf(UserInstanceStatus.class))).thenReturn(Collections.emptyList());
+        when(exploratoryDAO.fetchRunningExploratoryFieldsForProject(anyString())).thenReturn(getUserInstances());
+        when(securityService.getServiceAccountInfo(anyString())).thenReturn(getDataLabSystemUser());
+        when(projectService.get(anyString())).thenReturn(getProjectDTOWithStoppedEdge());
+
+        environmentService.stopAll();
+
+        verify(projectService).getProjects();
+        verify(exploratoryDAO).fetchProjectExploratoriesWhereStatusIn(PROJECT_NAME, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE);
+        verify(exploratoryDAO).fetchRunningExploratoryFieldsForProject(PROJECT_NAME);
+        verify(securityService, times(2)).getServiceAccountInfo(DATALAB_SYSTEM_USER);
+        verify(exploratoryService).stop(getDataLabSystemUser(), USER, PROJECT_NAME, EXPLORATORY_NAME_1, AUDIT_QUOTA_MESSAGE);
+        verify(exploratoryService).stop(getDataLabSystemUser(), USER, PROJECT_NAME, EXPLORATORY_NAME_2, AUDIT_QUOTA_MESSAGE);
+        verify(projectService).get(PROJECT_NAME);
+        verifyNoMoreInteractions(projectService, exploratoryDAO, securityService, exploratoryService);
+    }
+
+    @Test
+    public void stopEnvironmentWithServiceAccount() {
+        when(exploratoryDAO.fetchUserExploratoriesWhereStatusIn(anyString(), anyListOf(UserInstanceStatus.class))).thenReturn(Collections.emptyList());
+        when(exploratoryDAO.fetchRunningExploratoryFields(anyString())).thenReturn(getUserInstances());
+        when(securityService.getServiceAccountInfo(anyString())).thenReturn(getDataLabSystemUser());
+
+        environmentService.stopEnvironmentWithServiceAccount(USER);
+
+        verify(exploratoryDAO).fetchUserExploratoriesWhereStatusIn(USER, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE);
+        verify(exploratoryDAO).fetchRunningExploratoryFields(USER);
+        verify(securityService, times(2)).getServiceAccountInfo(DATALAB_SYSTEM_USER);
+        verify(exploratoryService).stop(getDataLabSystemUser(), USER, PROJECT_NAME, EXPLORATORY_NAME_1, AUDIT_QUOTA_MESSAGE);
+        verify(exploratoryService).stop(getDataLabSystemUser(), USER, PROJECT_NAME, EXPLORATORY_NAME_2, AUDIT_QUOTA_MESSAGE);
+        verifyNoMoreInteractions(exploratoryDAO, securityService, exploratoryService);
+    }
+
+    @Test(expected = ResourceConflictException.class)
+    public void stopEnvironmentWithServiceAccountWithException() {
+        when(exploratoryDAO.fetchUserExploratoriesWhereStatusIn(USER, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE))
+                .thenReturn(getUserInstances());
+
+        environmentService.stopEnvironmentWithServiceAccount(USER);
+
+        verify(exploratoryDAO).fetchUserExploratoriesWhereStatusIn(USER, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE);
+        verifyNoMoreInteractions(exploratoryDAO, securityService, exploratoryService);
+    }
+
+    @Test
+    public void getActiveUsersWithException() {
+        doThrow(new DatalabException("Users not found")).when(envDAO).fetchActiveEnvUsers();
+
+        expectedException.expect(DatalabException.class);
+        expectedException.expectMessage("Users not found");
+
+        environmentService.getUsers();
+    }
+
+    @Test
+    public void stopProjectEnvironment() {
+        final UserInfo userInfo = getUserInfo();
+        final ProjectDTO projectDTO = getProjectDTO();
+        when(exploratoryDAO.fetchRunningExploratoryFieldsForProject(anyString())).thenReturn(getUserInstances());
+        when(securityService.getServiceAccountInfo(anyString())).thenReturn(userInfo);
+        when(exploratoryService.stop(any(UserInfo.class), anyString(), anyString(), anyString(), anyString())).thenReturn(UUID);
+        when(projectService.get(anyString())).thenReturn(projectDTO);
+        doNothing().when(projectService).stop(any(UserInfo.class), anyString(), anyString(), anyString());
+
+        environmentService.stopProjectEnvironment(PROJECT_NAME);
+
+        verify(exploratoryDAO).fetchRunningExploratoryFieldsForProject(PROJECT_NAME);
+        verify(exploratoryService).stop(refEq(userInfo), eq(USER), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq(AUDIT_QUOTA_MESSAGE));
+        verify(exploratoryService).stop(refEq(userInfo), eq(USER), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_2), eq(AUDIT_QUOTA_MESSAGE));
+        verify(securityService, times(3)).getServiceAccountInfo(DATALAB_SYSTEM_USER);
+        verify(projectService).get(eq(PROJECT_NAME));
+        verify(projectService).stop(refEq(userInfo), eq(ENDPOINT_NAME), eq(PROJECT_NAME), eq(AUDIT_QUOTA_MESSAGE));
+        verify(exploratoryDAO).fetchProjectExploratoriesWhereStatusIn(PROJECT_NAME, Arrays.asList(UserInstanceStatus.CREATING,
+                UserInstanceStatus.STARTING, UserInstanceStatus.CREATING_IMAGE),
+                UserInstanceStatus.CREATING, UserInstanceStatus.STARTING, UserInstanceStatus.CREATING_IMAGE);
+        verifyNoMoreInteractions(exploratoryDAO, exploratoryService, projectService);
+    }
+
+    @Test
+    public void stopExploratory() {
+        final UserInfo userInfo = getUserInfo();
+        when(exploratoryService.stop(any(UserInfo.class), anyString(), anyString(), anyString(), anyString())).thenReturn(UUID);
+
+        environmentService.stopExploratory(userInfo, USER, PROJECT_NAME, EXPLORATORY_NAME_1);
+
+        verify(exploratoryService).stop(refEq(userInfo), eq(USER), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq(null));
+        verifyNoMoreInteractions(securityService, exploratoryService);
+    }
+
+    @Test
+    public void stopComputational() {
+        final UserInfo userInfo = getUserInfo();
+        doNothing().when(computationalService).stopSparkCluster(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString());
+
+        environmentService.stopComputational(userInfo, USER, PROJECT_NAME, EXPLORATORY_NAME_1, "compName");
+
+        verify(computationalService).stopSparkCluster(refEq(userInfo), eq(userInfo.getName()), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq("compName"),
+                eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME_1)));
+        verifyNoMoreInteractions(securityService, computationalService);
+    }
+
+    @Test
+    public void terminateExploratory() {
+        final UserInfo userInfo = getUserInfo();
+        when(exploratoryService.terminate(any(UserInfo.class), anyString(), anyString(), anyString(), anyString())).thenReturn(UUID);
+
+        environmentService.terminateExploratory(userInfo, USER, PROJECT_NAME, EXPLORATORY_NAME_1);
+
+        verify(exploratoryService).terminate(refEq(userInfo), eq(USER), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq(null));
+        verifyNoMoreInteractions(securityService, exploratoryService);
+    }
+
+    @Test
+    public void terminateComputational() {
+        final UserInfo userInfo = getUserInfo();
+        doNothing().when(computationalService)
+                .terminateComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString());
+
+        environmentService.terminateComputational(userInfo, USER, PROJECT_NAME, EXPLORATORY_NAME_1, "compName");
+
+        verify(computationalService).terminateComputational(refEq(userInfo), eq(userInfo.getName()), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq("compName"),
+                eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME_1)));
+        verifyNoMoreInteractions(securityService, computationalService);
+    }
+
+    private UserResourceInfo getUserResourceInfoEdge() {
+        return UserResourceInfo.builder()
+                .resourceType(ResourceEnum.EDGE_NODE)
+                .resourceStatus("running")
+                .project(PROJECT_NAME)
+                .endpoint(ENDPOINT_NAME)
+                .ip(null)
+                .build();
+    }
+
+    private UserResourceInfo getUserResourceInfo(String exploratoryName) {
+        return UserResourceInfo.builder()
+                .resourceType(ResourceEnum.NOTEBOOK)
+                .resourceName(exploratoryName)
+                .resourceShape(SHAPE)
+                .resourceStatus("running")
+                .computationalResources(Collections.emptyList())
+                .user(USER)
+                .project(PROJECT_NAME)
+                .endpoint(ENDPOINT_NAME)
+                .cloudProvider("aws")
+                .exploratoryUrls(null)
+                .build();
+    }
+
+    private UserInfo getUserInfo() {
+        return new UserInfo(USER, TOKEN);
+    }
+
+    private UserInfo getDataLabSystemUser() {
+        return new UserInfo(DATALAB_SYSTEM_USER, DATALAB_SYSTEM_USER_TOKEN);
+    }
+
+    private List<UserInstanceDTO> getUserInstances() {
+        return Arrays.asList(
+                new UserInstanceDTO().withExploratoryName(EXPLORATORY_NAME_1).withUser(USER).withProject(PROJECT_NAME).withEndpoint(ENDPOINT_NAME)
+                        .withShape(SHAPE).withStatus("running").withResources(Collections.emptyList()).withCloudProvider("aws"),
+                new UserInstanceDTO().withExploratoryName(EXPLORATORY_NAME_2).withUser(USER).withProject(PROJECT_NAME).withEndpoint(ENDPOINT_NAME)
+                        .withShape(SHAPE).withStatus("running").withResources(Collections.emptyList()).withCloudProvider("aws"));
+    }
+
+    private ProjectDTO getProjectDTO() {
+        return new ProjectDTO(PROJECT_NAME, Collections.emptySet(), "", "", null,
+                Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, new EdgeInfo())), true);
+    }
+
+    private ProjectDTO getProjectDTOWithStoppedEdge() {
+        return new ProjectDTO(PROJECT_NAME, Collections.emptySet(), "", "", null,
+                Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.STOPPED, new EdgeInfo())), true);
+    }
+
+    private ProjectDTO getProjectDTOWithoutEndpoint() {
+        return new ProjectDTO(PROJECT_NAME, Collections.emptySet(), "", "", null, null, true);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ExploratoryServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ExploratoryServiceImplTest.java
new file mode 100644
index 0000000..1af7730
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ExploratoryServiceImplTest.java
@@ -0,0 +1,549 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.ComputationalDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.GitCredsDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectEndpointDTO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.service.TagService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.StatusEnvBaseDTO;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.base.edge.EdgeInfo;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.dto.exploratory.ExploratoryActionDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryCreateDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryStatusDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.model.exploratory.Exploratory;
+import com.epam.datalab.rest.client.RESTService;
+import com.mongodb.client.result.UpdateResult;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import static java.util.Collections.singletonList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyListOf;
+import static org.mockito.Mockito.anyMapOf;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.anyVararg;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ExploratoryServiceImplTest {
+
+    private final String USER = "test";
+    private final String TOKEN = "token";
+    private final String PROJECT = "project";
+    private final String EXPLORATORY_NAME = "expName";
+    private final String UUID = "1234-56789765-4321";
+    private static final String ENDPOINT_NAME = "endpointName";
+
+
+    private UserInfo userInfo;
+    private UserInstanceDTO userInstance;
+    private StatusEnvBaseDTO statusEnvBaseDTO;
+
+    @Mock
+    private ProjectService projectService;
+    @Mock
+    private ExploratoryDAO exploratoryDAO;
+    @Mock
+    private ComputationalDAO computationalDAO;
+    @Mock
+    private GitCredsDAO gitCredsDAO;
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+    @Mock
+    private RESTService provisioningService;
+    @Mock
+    private RequestBuilder requestBuilder;
+    @Mock
+    private RequestId requestId;
+    @Mock
+    private TagService tagService;
+    @Mock
+    private EndpointService endpointService;
+    @Mock
+    private SelfServiceApplicationConfiguration configuration;
+    @InjectMocks
+    private ExploratoryServiceImpl exploratoryService;
+
+    @Before
+    public void setUp() {
+        when(configuration.isAuditEnabled()).thenReturn(false);
+        userInfo = getUserInfo();
+        userInstance = getUserInstanceDto();
+    }
+
+    @Test
+    public void start() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+
+        ExploratoryGitCredsDTO egcDtoMock = mock(ExploratoryGitCredsDTO.class);
+        when(gitCredsDAO.findGitCreds(anyString())).thenReturn(egcDtoMock);
+
+        ExploratoryActionDTO egcuDto = new ExploratoryGitCredsUpdateDTO();
+        egcuDto.withExploratoryName(EXPLORATORY_NAME);
+        when(requestBuilder.newExploratoryStart(any(UserInfo.class), any(UserInstanceDTO.class), any(EndpointDTO.class),
+                any(ExploratoryGitCredsDTO.class))).thenReturn(egcuDto);
+
+        String exploratoryStart = "exploratory/start";
+        when(provisioningService.post(anyString(), anyString(), any(ExploratoryActionDTO.class), any()))
+                .thenReturn(UUID);
+        when(requestId.put(anyString(), anyString())).thenReturn(UUID);
+
+        String uuid = exploratoryService.start(userInfo, EXPLORATORY_NAME, "project", null);
+        assertNotNull(uuid);
+        assertEquals(UUID, uuid);
+
+        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("starting");
+
+        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(provisioningService).post(endpointDTO().getUrl() + exploratoryStart, TOKEN, egcuDto, String.class);
+        verify(requestId).put(USER, UUID);
+        verifyNoMoreInteractions(exploratoryDAO, provisioningService, requestId);
+    }
+
+    @Test
+    public void startWhenMethodFetchExploratoryFieldsThrowsException() {
+        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
+        doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
+                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
+        try {
+            exploratoryService.start(userInfo, EXPLORATORY_NAME, PROJECT, null);
+        } catch (DatalabException e) {
+            assertEquals("Could not start exploratory environment expName: Exploratory for user with " +
+                    "name not found", e.getMessage());
+        }
+        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("starting");
+        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+
+        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("failed");
+        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
+        verifyNoMoreInteractions(exploratoryDAO);
+    }
+
+    @Test
+    public void stop() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
+        when(computationalDAO.updateComputationalStatusesForExploratory(any(StatusEnvBaseDTO.class))).thenReturn(1);
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+
+        ExploratoryActionDTO eaDto = new ExploratoryActionDTO();
+        eaDto.withExploratoryName(EXPLORATORY_NAME);
+        when(requestBuilder.newExploratoryStop(anyString(), any(UserInstanceDTO.class), any(EndpointDTO.class)))
+                .thenReturn(eaDto);
+
+        String exploratoryStop = "exploratory/stop";
+        when(provisioningService.post(anyString(), anyString(), any(ExploratoryActionDTO.class), any())).thenReturn
+                (UUID);
+        when(requestId.put(anyString(), anyString())).thenReturn(UUID);
+
+        String uuid = exploratoryService.stop(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, null);
+        assertNotNull(uuid);
+        assertEquals(UUID, uuid);
+
+        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("stopping");
+
+        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(provisioningService).post(endpointDTO().getUrl() + exploratoryStop, TOKEN, eaDto, String.class);
+        verify(computationalDAO).updateComputationalStatusesForExploratory(userInfo.getName(), PROJECT,
+                EXPLORATORY_NAME, UserInstanceStatus.STOPPING, UserInstanceStatus.TERMINATING,
+                UserInstanceStatus.FAILED, UserInstanceStatus.TERMINATED, UserInstanceStatus.STOPPED);
+        verify(requestId).put(USER, UUID);
+        verifyNoMoreInteractions(exploratoryDAO, provisioningService, requestId);
+    }
+
+    @Test
+    public void stopWhenMethodFetchExploratoryFieldsThrowsException() {
+        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
+        doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
+                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
+        try {
+            exploratoryService.stop(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, null);
+        } catch (DatalabException e) {
+            assertEquals("Could not stop exploratory environment expName: Exploratory for user with " +
+                    "name not found", e.getMessage());
+        }
+        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("stopping");
+        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+
+        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("failed");
+        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
+        verifyNoMoreInteractions(exploratoryDAO);
+    }
+
+    @Test
+    public void terminate() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
+        when(computationalDAO.updateComputationalStatusesForExploratory(any(StatusEnvBaseDTO.class))).thenReturn(1);
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+
+        ExploratoryActionDTO eaDto = new ExploratoryActionDTO();
+        eaDto.withExploratoryName(EXPLORATORY_NAME);
+        when(requestBuilder.newExploratoryStop(anyString(), any(UserInstanceDTO.class), any(EndpointDTO.class)))
+                .thenReturn(eaDto);
+
+        String exploratoryTerminate = "exploratory/terminate";
+        when(provisioningService.post(anyString(), anyString(), any(ExploratoryActionDTO.class), any())).thenReturn
+                (UUID);
+        when(requestId.put(anyString(), anyString())).thenReturn(UUID);
+
+        String uuid = exploratoryService.terminate(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, null);
+        assertNotNull(uuid);
+        assertEquals(UUID, uuid);
+
+        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("terminating");
+
+        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(computationalDAO).updateComputationalStatusesForExploratory(USER, PROJECT, EXPLORATORY_NAME,
+                UserInstanceStatus.TERMINATING, UserInstanceStatus.TERMINATING, UserInstanceStatus.TERMINATED,
+                UserInstanceStatus.FAILED);
+        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);
+    }
+
+    @Test
+    public void terminateWhenMethodFetchExploratoryFieldsThrowsException() {
+        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
+        doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
+                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
+        try {
+            exploratoryService.terminate(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, null);
+        } catch (DatalabException e) {
+            assertEquals("Could not terminate exploratory environment expName: Exploratory for user " +
+                    "with name not found", e.getMessage());
+        }
+        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("terminating");
+        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+
+        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("failed");
+        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
+        verifyNoMoreInteractions(exploratoryDAO);
+    }
+
+    @Test
+    public void create() {
+        ProjectDTO projectDTO = getProjectDTO();
+        when(projectService.get(anyString())).thenReturn(projectDTO);
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        doNothing().when(exploratoryDAO).insertExploratory(any(UserInstanceDTO.class));
+        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);
+
+        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);
+        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(DatalabException.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() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        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", "exploratory");
+        } catch (DatalabException e) {
+            assertEquals("Could not create exploratory environment expName for user test: null",
+                    e.getMessage());
+        }
+        userInstance.withStatus("creating");
+        userInstance.withResources(Collections.emptyList());
+        verify(exploratoryDAO).insertExploratory(userInstance);
+        verify(exploratoryDAO, never()).updateExploratoryStatus(any(StatusEnvBaseDTO.class));
+        verify(endpointService).get("test");
+        verifyNoMoreInteractions(exploratoryDAO);
+    }
+
+    @Test
+    public void createWhenMethodNewExploratoryCreateThrowsException() {
+        ProjectDTO projectDTO = getProjectDTO();
+        when(projectService.get(anyString())).thenReturn(projectDTO);
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        doNothing().when(exploratoryDAO).insertExploratory(any(UserInstanceDTO.class));
+        ExploratoryGitCredsDTO egcDto = new ExploratoryGitCredsDTO();
+        when(gitCredsDAO.findGitCreds(anyString())).thenReturn(egcDto);
+
+        Exploratory exploratory = Exploratory.builder().name(EXPLORATORY_NAME).endpoint("test").build();
+
+        doThrow(new DatalabException("Cannot create instance of resource class ")).when(requestBuilder)
+                .newExploratoryCreate(any(ProjectDTO.class), any(EndpointDTO.class), any(Exploratory.class),
+                        any(UserInfo.class), any(ExploratoryGitCredsDTO.class), anyMapOf(String.class, String.class));
+
+        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
+        try {
+            exploratoryService.create(userInfo, exploratory, "project", "exploratory");
+        } catch (DatalabException e) {
+            assertEquals("Could not create exploratory environment expName for user test: Cannot create instance " +
+                    "of resource class ", e.getMessage());
+        }
+
+        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("failed");
+
+        userInstance.withStatus("creating");
+        userInstance.withResources(Collections.emptyList());
+        verify(projectService).get("project");
+        verify(exploratoryDAO).insertExploratory(userInstance);
+        verify(exploratoryDAO).insertExploratory(userInstance);
+        verify(gitCredsDAO).findGitCreds(USER);
+        verify(requestBuilder).newExploratoryCreate(projectDTO, endpointDTO(), exploratory, userInfo, egcDto, Collections.emptyMap());
+        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
+        verifyNoMoreInteractions(projectService, exploratoryDAO, gitCredsDAO, requestBuilder);
+    }
+
+    @Test
+    public void updateProjectExploratoryStatuses() {
+        when(exploratoryDAO.fetchProjectExploratoriesWhereStatusNotIn(anyString(), anyString(), anyVararg()))
+                .thenReturn(singletonList(userInstance));
+        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
+        doNothing().when(computationalDAO).updateComputationalStatusesForExploratory(anyString(), anyString(),
+                anyString(), any(UserInstanceStatus.class), any(UserInstanceStatus.class), anyVararg());
+
+        exploratoryService.updateProjectExploratoryStatuses(userInfo, "project",
+                "endpoint", UserInstanceStatus.TERMINATING);
+        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("terminating");
+
+        verify(exploratoryDAO).fetchProjectExploratoriesWhereStatusNotIn("project", "endpoint",
+                UserInstanceStatus.TERMINATED, UserInstanceStatus.FAILED);
+        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
+        verify(computationalDAO).updateComputationalStatusesForExploratory(USER, PROJECT,
+                EXPLORATORY_NAME, UserInstanceStatus.TERMINATING, UserInstanceStatus.TERMINATING,
+                UserInstanceStatus.TERMINATED, UserInstanceStatus.FAILED);
+
+        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
+    }
+
+    @Test
+    public void getUserInstance() {
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+
+        Optional<UserInstanceDTO> expectedInstance = Optional.of(userInstance);
+        Optional<UserInstanceDTO> actualInstance = exploratoryService.getUserInstance(USER, PROJECT, EXPLORATORY_NAME);
+        assertEquals(expectedInstance, actualInstance);
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(exploratoryDAO);
+    }
+
+    @Test
+    public void getUserInstanceWithException() {
+        doThrow(new ResourceNotFoundException("Exploratory for user not found"))
+                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
+
+        Optional<UserInstanceDTO> expectedInstance = Optional.empty();
+        Optional<UserInstanceDTO> actualInstance = exploratoryService.getUserInstance(USER, PROJECT, EXPLORATORY_NAME);
+        assertEquals(expectedInstance, actualInstance);
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(exploratoryDAO);
+    }
+
+    @Test
+    public void testUpdateExploratoryClusterConfig() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
+        when(requestBuilder.newClusterConfigUpdate(any(UserInfo.class), any(UserInstanceDTO.class),
+                anyListOf(ClusterConfig.class), any(EndpointDTO.class))).thenReturn(new ExploratoryReconfigureSparkClusterActionDTO());
+        when(provisioningService.post(anyString(), anyString(), any(ExploratoryReconfigureSparkClusterActionDTO.class)
+                , any())).thenReturn(UUID);
+
+        exploratoryService.updateClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME, singletonList(new ClusterConfig()));
+
+        verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(requestBuilder).newClusterConfigUpdate(refEq(getUserInfo()), refEq(getUserInstanceDto()),
+                refEq(singletonList(new ClusterConfig())), refEq(endpointDTO()));
+        verify(requestId).put(USER, UUID);
+        verify(provisioningService).post(eq(endpointDTO().getUrl() + "exploratory/reconfigure_spark"), eq(TOKEN),
+                refEq(new ExploratoryReconfigureSparkClusterActionDTO(), "self"), eq(String.class));
+        verify(exploratoryDAO).updateExploratoryFields(refEq(new ExploratoryStatusDTO()
+                .withUser(USER)
+                .withProject(PROJECT)
+                .withConfig(singletonList(new ClusterConfig()))
+                .withStatus(UserInstanceStatus.RECONFIGURING.toString())
+                .withExploratoryName(EXPLORATORY_NAME), "self"));
+        verifyNoMoreInteractions(requestBuilder, requestId, exploratoryDAO, provisioningService);
+    }
+
+    @Test
+    public void testUpdateExploratoryClusterConfigWhenNotRunning() {
+
+        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenThrow(new ResourceNotFoundException("EXCEPTION"));
+
+        try {
+
+            exploratoryService.updateClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME,
+                    singletonList(new ClusterConfig()));
+        } catch (ResourceNotFoundException e) {
+            assertEquals("EXCEPTION", e.getMessage());
+        }
+
+        verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(exploratoryDAO);
+        verifyZeroInteractions(requestBuilder, requestId, provisioningService);
+    }
+
+    @Test
+    public void testGetClusterConfig() {
+        when(exploratoryDAO.getClusterConfig(anyString(), anyString(), anyString())).thenReturn(Collections.singletonList(getClusterConfig()));
+        final List<ClusterConfig> clusterConfig = exploratoryService.getClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME);
+
+        assertEquals(1, clusterConfig.size());
+        assertEquals("classification", clusterConfig.get(0).getClassification());
+
+        verify(exploratoryDAO).getClusterConfig(getUserInfo().getName(), PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(exploratoryDAO);
+    }
+
+    @Test
+    public void testGetClusterConfigWithException() {
+        when(exploratoryDAO.getClusterConfig(anyString(), anyString(), anyString())).thenThrow(new RuntimeException("Exception"));
+
+        expectedException.expect(RuntimeException.class);
+        expectedException.expectMessage("Exception");
+        exploratoryService.getClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME);
+    }
+
+    private ClusterConfig getClusterConfig() {
+        final ClusterConfig config = new ClusterConfig();
+        config.setClassification("classification");
+        return config;
+    }
+
+    private UserInfo getUserInfo() {
+        return new UserInfo(USER, TOKEN);
+    }
+
+    private UserInstanceDTO getUserInstanceDto() {
+        UserComputationalResource compResource = new UserComputationalResource();
+        compResource.setImageName("YYYY.dataengine");
+        compResource.setComputationalName("compName");
+        compResource.setStatus("stopped");
+        compResource.setComputationalId("compId");
+        return new UserInstanceDTO()
+                .withUser(USER)
+                .withExploratoryName(EXPLORATORY_NAME)
+                .withStatus("running")
+                .withResources(singletonList(compResource))
+                .withTags(Collections.emptyMap())
+                .withProject(PROJECT)
+                .withEndpoint("test")
+                .withCloudProvider(CloudProvider.AWS.toString());
+    }
+
+    private StatusEnvBaseDTO getStatusEnvBaseDTOWithStatus(String status) {
+        return new ExploratoryStatusDTO()
+                .withProject(PROJECT)
+                .withUser(USER)
+                .withExploratoryName(EXPLORATORY_NAME)
+                .withStatus(status);
+    }
+
+    private EndpointDTO endpointDTO() {
+        return new EndpointDTO("test", "url", "", null, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
+    }
+
+    private ProjectDTO getProjectDTO() {
+        return new ProjectDTO("project", Collections.emptySet(), "", "", null,
+                singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING,
+                        new EdgeInfo())), true);
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/GitCredentialServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/GitCredentialServiceImplTest.java
new file mode 100644
index 0000000..a54483a
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/GitCredentialServiceImplTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.GitCredsDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class GitCredentialServiceImplTest {
+
+	private final String USER = "test";
+
+	@Mock
+	private GitCredsDAO gitCredsDAO;
+	@Mock
+	private ExploratoryDAO exploratoryDAO;
+	@Mock
+	private RESTService provisioningService;
+	@Mock
+	private RequestBuilder requestBuilder;
+	@Mock
+	private RequestId requestId;
+	@Mock
+	private EndpointService endpointService;
+
+	@InjectMocks
+	private GitCredentialServiceImpl gitCredentialService;
+
+	@Test
+	public void updateGitCredentials() {
+		String token = "token";
+		UserInfo userInfo = new UserInfo(USER, token);
+		doNothing().when(gitCredsDAO).updateGitCreds(anyString(), any(ExploratoryGitCredsDTO.class));
+		when(endpointService.get(anyString())).thenReturn(endpointDTO());
+
+		String exploratoryName = "explName";
+		UserInstanceDTO uiDto = new UserInstanceDTO().withExploratoryName(exploratoryName).withUser(USER);
+		when(exploratoryDAO.fetchRunningExploratoryFields(anyString())).thenReturn(Collections.singletonList(uiDto));
+
+		ExploratoryGitCredsUpdateDTO egcuDto = new ExploratoryGitCredsUpdateDTO().withExploratoryName(exploratoryName);
+		when(requestBuilder.newGitCredentialsUpdate(any(UserInfo.class), any(UserInstanceDTO.class), any(EndpointDTO.class),
+				any(ExploratoryGitCredsDTO.class))).thenReturn(egcuDto);
+
+		String uuid = "someUuid";
+		when(provisioningService.post(anyString(), anyString(), any(ExploratoryGitCredsUpdateDTO.class), any()))
+				.thenReturn(uuid);
+		when(requestId.put(anyString(), anyString())).thenReturn(uuid);
+
+		ExploratoryGitCredsDTO egcDto = new ExploratoryGitCredsDTO();
+		gitCredentialService.updateGitCredentials(userInfo, egcDto);
+
+		verify(gitCredsDAO).updateGitCreds(USER, egcDto);
+		verify(exploratoryDAO).fetchRunningExploratoryFields(USER);
+		verify(requestBuilder).newGitCredentialsUpdate(userInfo, uiDto, endpointDTO(), egcDto);
+		verify(provisioningService).post(endpointDTO().getUrl() + "exploratory/git_creds", token, egcuDto,
+				String.class);
+		verify(requestId).put(USER, uuid);
+		verifyNoMoreInteractions(gitCredsDAO, exploratoryDAO, requestBuilder, provisioningService, requestId);
+	}
+
+	@Test
+	public void updateGitCredentialsWhenMethodUpdateGitCredsThrowsException() {
+		String token = "token";
+		UserInfo userInfo = new UserInfo(USER, token);
+		doThrow(new NullPointerException())
+				.when(gitCredsDAO).updateGitCreds(anyString(), any(ExploratoryGitCredsDTO.class));
+
+		ExploratoryGitCredsDTO egcDto = new ExploratoryGitCredsDTO();
+		try {
+			gitCredentialService.updateGitCredentials(userInfo, egcDto);
+		} catch (DatalabException e) {
+			assertEquals("Cannot update the GIT credentials: null", e.getMessage());
+		}
+
+		verify(gitCredsDAO).updateGitCreds(USER, egcDto);
+		verifyNoMoreInteractions(gitCredsDAO);
+	}
+
+	@Test
+	public void updateGitCredentialsWithFailedNotebooks() {
+		when(endpointService.get(anyString())).thenReturn(endpointDTO());
+		String token = "token";
+		UserInfo userInfo = new UserInfo(USER, token);
+		doNothing().when(gitCredsDAO).updateGitCreds(anyString(), any(ExploratoryGitCredsDTO.class));
+
+		String exploratoryName = "explName";
+		UserInstanceDTO uiDto = new UserInstanceDTO().withExploratoryName(exploratoryName).withUser(USER);
+		when(exploratoryDAO.fetchRunningExploratoryFields(anyString())).thenReturn(Collections.singletonList(uiDto));
+
+		doThrow(new DatalabException("Cannot create instance of resource class "))
+				.when(requestBuilder).newGitCredentialsUpdate(any(UserInfo.class), any(UserInstanceDTO.class),
+				any(EndpointDTO.class), any(ExploratoryGitCredsDTO.class));
+
+		ExploratoryGitCredsDTO egcDto = new ExploratoryGitCredsDTO();
+		try {
+			gitCredentialService.updateGitCredentials(userInfo, egcDto);
+		} catch (DatalabException e) {
+			assertEquals("Cannot update the GIT credentials: Requests for notebooks failed: explName",
+					e.getMessage());
+		}
+
+		verify(gitCredsDAO).updateGitCreds(USER, egcDto);
+		verify(exploratoryDAO).fetchRunningExploratoryFields(USER);
+		verify(requestBuilder).newGitCredentialsUpdate(userInfo, uiDto, endpointDTO(), egcDto);
+		verifyNoMoreInteractions(gitCredsDAO, exploratoryDAO, requestBuilder);
+	}
+
+	@Test
+	public void getGitCredentials() {
+		ExploratoryGitCredsDTO expectedEgcDto = new ExploratoryGitCredsDTO();
+		when(gitCredsDAO.findGitCreds(anyString(), anyBoolean())).thenReturn(expectedEgcDto);
+
+		ExploratoryGitCredsDTO actualEgcDto = gitCredentialService.getGitCredentials(USER);
+		assertNotNull(actualEgcDto);
+		assertEquals(expectedEgcDto, actualEgcDto);
+
+		verify(gitCredsDAO).findGitCreds(USER, true);
+		verifyNoMoreInteractions(gitCredsDAO);
+	}
+
+	@Test
+	public void getGitCredentialsWhenMethodFindGitCredsThrowsException() {
+		doThrow(new NullPointerException()).when(gitCredsDAO).findGitCreds(anyString(), anyBoolean());
+		try {
+			gitCredentialService.getGitCredentials(USER);
+		} catch (DatalabException e) {
+			assertEquals("Cannot load GIT credentials for user test: null", e.getMessage());
+		}
+		verify(gitCredsDAO).findGitCreds(USER, true);
+		verifyNoMoreInteractions(gitCredsDAO);
+	}
+
+	private EndpointDTO endpointDTO() {
+		return new EndpointDTO("test", "url", "", null, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
+	}
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImplTest.java
new file mode 100644
index 0000000..78eb81f
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImplTest.java
@@ -0,0 +1,352 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryLibDAO;
+import com.epam.datalab.backendapi.dao.ImageExploratoryDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryImageDTO;
+import com.epam.datalab.dto.exploratory.ExploratoryStatusDTO;
+import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.epam.datalab.dto.exploratory.LibStatus;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceAlreadyExistException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.model.ResourceType;
+import com.epam.datalab.model.exploratory.Image;
+import com.epam.datalab.model.library.Library;
+import com.epam.datalab.rest.client.RESTService;
+import com.mongodb.client.result.UpdateResult;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.anyVararg;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ImageExploratoryServiceImplTest {
+    private final static String AUDIT_MESSAGE = "Image name: %s";
+    private final String USER = "test";
+    private final String TOKEN = "token";
+    private final String EXPLORATORY_NAME = "expName";
+    private final String PROJECT = "project";
+
+    private UserInfo userInfo;
+    private UserInstanceDTO userInstance;
+    private Image image;
+
+    @Mock
+    private ExploratoryDAO exploratoryDAO;
+    @Mock
+    private ImageExploratoryDAO imageExploratoryDao;
+    @Mock
+    private ExploratoryLibDAO libDAO;
+    @Mock
+    private RESTService provisioningService;
+    @Mock
+    private RequestBuilder requestBuilder;
+    @Mock
+    private EndpointService endpointService;
+    @Mock
+    private ProjectService projectService;
+
+    @InjectMocks
+    private ImageExploratoryServiceImpl imageExploratoryService;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Before
+    public void setUp() {
+        userInfo = getUserInfo();
+        userInstance = getUserInstanceDto();
+        image = fetchImage();
+    }
+
+    @Test
+    public void createImage() {
+        when(projectService.get(anyString())).thenReturn(getProjectDTO());
+        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        when(imageExploratoryDao.exist(anyString(), anyString())).thenReturn(false);
+
+        when(libDAO.getLibraries(anyString(), anyString(), anyString())).thenReturn(Collections.singletonList(getLibrary()));
+        doNothing().when(imageExploratoryDao).save(any(Image.class));
+        when(exploratoryDAO.updateExploratoryStatus(any(ExploratoryStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+        ExploratoryImageDTO eiDto = new ExploratoryImageDTO();
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(requestBuilder.newExploratoryImageCreate(any(UserInfo.class), any(UserInstanceDTO.class), anyString(),
+                any(EndpointDTO.class), any(ProjectDTO.class))).thenReturn(eiDto);
+
+        String expectedUuid = "someUuid";
+        when(provisioningService.post(anyString(), anyString(), any(ExploratoryImageDTO.class), any()))
+                .thenReturn(expectedUuid);
+
+        String imageName = "someImageName", imageDescription = "someDescription";
+        String actualUuid = imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME,
+                imageName, imageDescription, String.format(AUDIT_MESSAGE, imageName));
+        assertNotNull(actualUuid);
+        assertEquals(expectedUuid, actualUuid);
+
+        verify(projectService).get(PROJECT);
+        verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(exploratoryDAO).updateExploratoryStatus(any(ExploratoryStatusDTO.class));
+        verify(imageExploratoryDao).exist(imageName, PROJECT);
+        verify(imageExploratoryDao).save(any(Image.class));
+        verify(libDAO).getLibraries(USER, PROJECT, EXPLORATORY_NAME);
+        verify(requestBuilder).newExploratoryImageCreate(userInfo, userInstance, imageName, endpointDTO(), getProjectDTO());
+        verify(endpointService).get(anyString());
+        verify(provisioningService).post(endpointDTO().getUrl() + "exploratory/image", TOKEN, eiDto, String.class);
+        verifyNoMoreInteractions(projectService, exploratoryDAO, imageExploratoryDao, libDAO, requestBuilder, endpointService, provisioningService);
+    }
+
+    @Test
+    public void createImageWhenMethodFetchRunningExploratoryFieldsThrowsException() {
+        doThrow(new DatalabException("Running exploratory instance for user with name not found."))
+                .when(exploratoryDAO).fetchRunningExploratoryFields(anyString(), anyString(), anyString());
+
+        String imageName = "someImageName", imageDescription = "someDescription";
+
+        try {
+            imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME, imageName, imageDescription, String.format(AUDIT_MESSAGE, imageName));
+        } catch (DatalabException e) {
+            assertEquals("Running exploratory instance for user with name not found.", e.getMessage());
+        }
+        verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(exploratoryDAO);
+    }
+
+    @Test
+    public void createImageWhenResourceAlreadyExists() {
+        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        when(imageExploratoryDao.exist(anyString(), anyString())).thenReturn(true);
+
+        expectedException.expect(ResourceAlreadyExistException.class);
+        expectedException.expectMessage("Image with name someImageName is already exist");
+
+        String imageName = "someImageName", imageDescription = "someDescription";
+        imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME, imageName, imageDescription, String.format(AUDIT_MESSAGE, imageName));
+    }
+
+    @Test
+    public void createImageWhenMethodNewExploratoryImageCreateThrowsException() {
+        when(projectService.get(anyString())).thenReturn(getProjectDTO());
+        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        when(imageExploratoryDao.exist(anyString(), anyString())).thenReturn(false);
+
+        when(libDAO.getLibraries(anyString(), anyString(), anyString())).thenReturn(Collections.singletonList(getLibrary()));
+        doNothing().when(imageExploratoryDao).save(any(Image.class));
+        when(exploratoryDAO.updateExploratoryStatus(any(ExploratoryStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+        doThrow(new DatalabException("Cannot create instance of resource class")).when(requestBuilder)
+                .newExploratoryImageCreate(any(UserInfo.class), any(UserInstanceDTO.class), anyString(), any(EndpointDTO.class), any(ProjectDTO.class));
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+
+        String imageName = "someImageName", imageDescription = "someDescription";
+        try {
+            imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME, imageName, imageDescription, String.format(AUDIT_MESSAGE, imageName));
+        } catch (DatalabException e) {
+            assertEquals("Cannot create instance of resource class", e.getMessage());
+        }
+
+        verify(projectService).get(PROJECT);
+        verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(exploratoryDAO).updateExploratoryStatus(any(ExploratoryStatusDTO.class));
+        verify(imageExploratoryDao).exist(imageName, PROJECT);
+        verify(imageExploratoryDao).save(any(Image.class));
+        verify(libDAO).getLibraries(USER, PROJECT, EXPLORATORY_NAME);
+        verify(requestBuilder).newExploratoryImageCreate(userInfo, userInstance, imageName, endpointDTO(), getProjectDTO());
+        verify(endpointService).get(anyString());
+        verifyNoMoreInteractions(projectService, exploratoryDAO, imageExploratoryDao, libDAO, requestBuilder, endpointService);
+    }
+
+    @Test
+    public void finishImageCreate() {
+        when(exploratoryDAO.updateExploratoryStatus(any(ExploratoryStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+        doNothing().when(imageExploratoryDao).updateImageFields(any(Image.class));
+        doNothing().when(exploratoryDAO).updateExploratoryIp(anyString(), anyString(), anyString(), anyString());
+
+        String notebookIp = "someIp";
+        imageExploratoryService.finishImageCreate(image, EXPLORATORY_NAME, notebookIp);
+
+        verify(exploratoryDAO).updateExploratoryStatus(any(ExploratoryStatusDTO.class));
+        verify(exploratoryDAO).updateExploratoryIp(USER, PROJECT, notebookIp, EXPLORATORY_NAME);
+        verify(imageExploratoryDao).updateImageFields(image);
+        verifyNoMoreInteractions(exploratoryDAO, imageExploratoryDao);
+    }
+
+    @Test
+    public void finishImageCreateWhenMethodUpdateExploratoryIpThrowsException() {
+        when(exploratoryDAO.updateExploratoryStatus(any(ExploratoryStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+        doNothing().when(imageExploratoryDao).updateImageFields(any(Image.class));
+        doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
+                .when(exploratoryDAO).updateExploratoryIp(anyString(), anyString(), anyString(), anyString());
+
+        String notebookIp = "someIp";
+        try {
+            imageExploratoryService.finishImageCreate(image, EXPLORATORY_NAME, notebookIp);
+        } catch (ResourceNotFoundException e) {
+            assertEquals("Exploratory for user with name not found", e.getMessage());
+        }
+
+        verify(exploratoryDAO).updateExploratoryStatus(any(ExploratoryStatusDTO.class));
+        verify(exploratoryDAO).updateExploratoryIp(USER, PROJECT, notebookIp, EXPLORATORY_NAME);
+        verify(imageExploratoryDao).updateImageFields(image);
+        verifyNoMoreInteractions(exploratoryDAO, imageExploratoryDao);
+    }
+
+    @Test
+    public void finishImageCreateWhenNotebookIpIsNull() {
+        when(exploratoryDAO.updateExploratoryStatus(any(ExploratoryStatusDTO.class)))
+                .thenReturn(mock(UpdateResult.class));
+        doNothing().when(imageExploratoryDao).updateImageFields(any(Image.class));
+
+        imageExploratoryService.finishImageCreate(image, EXPLORATORY_NAME, null);
+
+        verify(exploratoryDAO).updateExploratoryStatus(any(ExploratoryStatusDTO.class));
+        verify(exploratoryDAO, never()).updateExploratoryIp(USER, PROJECT, null, EXPLORATORY_NAME);
+        verify(imageExploratoryDao).updateImageFields(image);
+        verifyNoMoreInteractions(exploratoryDAO, imageExploratoryDao);
+    }
+
+    @Test
+    public void getCreatedImages() {
+        ImageInfoRecord imageInfoRecord = getImageInfoRecord();
+        List<ImageInfoRecord> expectedRecordList = Collections.singletonList(imageInfoRecord);
+        when(imageExploratoryDao.getImages(anyString(), anyString(), anyString(), anyString(), anyVararg()))
+                .thenReturn(expectedRecordList);
+
+        List<ImageInfoRecord> actualRecordList = imageExploratoryService.getNotFailedImages(USER,
+                "someImage", "someProject", "someEndpoint");
+        assertNotNull(actualRecordList);
+        assertEquals(1, actualRecordList.size());
+        assertEquals(expectedRecordList, actualRecordList);
+
+        verify(imageExploratoryDao).getImages(USER, "someImage", "someProject", "someEndpoint", ImageStatus.CREATED, ImageStatus.CREATING);
+        verifyNoMoreInteractions(imageExploratoryDao);
+    }
+
+    @Test
+    public void getImage() {
+        ImageInfoRecord expectedImageInfoRecord = getImageInfoRecord();
+        when(imageExploratoryDao.getImage(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(Optional.of(expectedImageInfoRecord));
+
+        ImageInfoRecord actualImageInfoRecord = imageExploratoryService.getImage(USER, "someName", "someProject", "someEndpoint");
+        assertNotNull(actualImageInfoRecord);
+        assertEquals(expectedImageInfoRecord, actualImageInfoRecord);
+
+        verify(imageExploratoryDao).getImage(USER, "someName", "someProject", "someEndpoint");
+        verifyNoMoreInteractions(imageExploratoryDao);
+    }
+
+    @Test
+    public void getImageWhenMethodGetImageReturnsOptionalEmpty() {
+        when(imageExploratoryDao.getImage(anyString(), anyString(), anyString(), anyString())).thenReturn(Optional.empty());
+        expectedException.expect(ResourceNotFoundException.class);
+        expectedException.expectMessage(String.format("Image with name %s was not found for user %s",
+                "someImageName", USER));
+        imageExploratoryService.getImage(USER, "someImageName", "someProject", "someEndpoint");
+    }
+
+    @Test
+    public void getImagesForProject() {
+        when(imageExploratoryDao.getImagesForProject(anyString())).thenReturn(Collections.singletonList(getImageInfoRecord()));
+
+        imageExploratoryService.getImagesForProject(PROJECT);
+
+        verify(imageExploratoryDao).getImagesForProject(PROJECT);
+        verifyNoMoreInteractions(imageExploratoryDao);
+    }
+
+    private ImageInfoRecord getImageInfoRecord() {
+        return new ImageInfoRecord("someName", "someDescription", "someProject", "someEndpoint", "someUser", "someApp",
+                "someFullName", ImageStatus.CREATED);
+    }
+
+    private Image fetchImage() {
+        return Image.builder()
+                .name("someImageName")
+                .description("someDescription")
+                .status(ImageStatus.CREATING)
+                .user(USER)
+                .project(PROJECT)
+                .libraries(Collections.singletonList(getLibrary()))
+                .computationalLibraries(Collections.emptyMap())
+                .dockerImage("someImageName")
+                .exploratoryId("explId").build();
+    }
+
+    private Library getLibrary() {
+        return new Library("someGroup", "someName", "someVersion", LibStatus.INSTALLED,
+                "someErrorMessage").withType(ResourceType.EXPLORATORY);
+    }
+
+    private UserInstanceDTO getUserInstanceDto() {
+        return new UserInstanceDTO()
+                .withUser(USER)
+                .withExploratoryName(EXPLORATORY_NAME)
+                .withExploratoryId("explId")
+                .withProject(PROJECT);
+    }
+
+    private UserInfo getUserInfo() {
+        return new UserInfo(USER, TOKEN);
+    }
+
+    private EndpointDTO endpointDTO() {
+        return new EndpointDTO("test", "url", "", null, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
+    }
+
+    private ProjectDTO getProjectDTO() {
+        return ProjectDTO.builder().name(PROJECT).build();
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImplTest.java
new file mode 100644
index 0000000..e44ee54
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImplTest.java
@@ -0,0 +1,387 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.domain.BillingReport;
+import com.epam.datalab.backendapi.domain.BillingReportLine;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.domain.ProjectEndpointDTO;
+import com.epam.datalab.backendapi.resources.TestBase;
+import com.epam.datalab.backendapi.resources.dto.HealthStatusPageDTO;
+import com.epam.datalab.backendapi.resources.dto.ProjectInfrastructureInfo;
+import com.epam.datalab.backendapi.service.BillingService;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.service.ProjectService;
+import com.epam.datalab.dto.InfrastructureMetaInfoDTO;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.aws.edge.EdgeInfoAws;
+import com.epam.datalab.dto.azure.edge.EdgeInfoAzure;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.billing.BillingResourceType;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.dto.gcp.edge.EdgeInfoGcp;
+import com.jcabi.manifests.Manifests;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class InfrastructureInfoServiceImplTest extends TestBase {
+
+    private static final String PROJECT = "project";
+    private static final String EXPLORATORY_NAME = "exploratoryName";
+    private static final String COMPUTE_NAME = "computeName";
+    private static final String CURRENCY = "currency";
+
+    @Mock
+    private ExploratoryDAO expDAO;
+    @Mock
+    private SelfServiceApplicationConfiguration configuration;
+    @Mock
+    private ProjectService projectService;
+    @Mock
+    private EndpointService endpointService;
+    @Mock
+    private BillingService billingService;
+
+    @InjectMocks
+    private InfrastructureInfoServiceImpl infoService;
+
+    @Test
+    public void getUserResources() {
+        when(endpointService.getEndpoints()).thenReturn(Collections.singletonList(getEndpointDTO()));
+        when(projectService.getUserProjects(any(UserInfo.class), anyBoolean())).thenReturn(Collections.singletonList(getProjectDTO()));
+        when(expDAO.findExploratories(anyString(), anyString())).thenReturn(getUserInstanceDTOs());
+        when(billingService.getBillingProjectQuoteUsed(anyString())).thenReturn(10);
+        when(projectService.get(anyString())).thenReturn(getProjectDTO());
+        when(billingService.getExploratoryBillingData(anyString(), anyString(), anyString(), anyListOf(String.class))).thenReturn(getReport());
+
+        List<ProjectInfrastructureInfo> actualUserResources = infoService.getUserResources(getUserInfo());
+
+        assertEquals("resources should be equal", getProjectInfrastructureInfo(), actualUserResources);
+        verify(endpointService).getEndpoints();
+        verify(projectService).getUserProjects(getUserInfo(), Boolean.FALSE);
+        verify(expDAO).findExploratories(USER.toLowerCase(), PROJECT);
+        verify(billingService).getBillingProjectQuoteUsed(PROJECT);
+        verify(projectService).get(PROJECT);
+        verify(billingService).getExploratoryBillingData(PROJECT, ENDPOINT_NAME, EXPLORATORY_NAME, Collections.singletonList(COMPUTE_NAME));
+        verifyNoMoreInteractions(endpointService, projectService, expDAO, billingService);
+    }
+
+    @Test
+    public void getAwsUserResources() {
+        when(endpointService.getEndpoints()).thenReturn(Collections.singletonList(getEndpointDTO()));
+        when(projectService.getUserProjects(any(UserInfo.class), anyBoolean())).thenReturn(Collections.singletonList(getAwsProjectDTO()));
+        when(expDAO.findExploratories(anyString(), anyString())).thenReturn(getUserInstanceDTOs());
+        when(billingService.getBillingProjectQuoteUsed(anyString())).thenReturn(10);
+        when(projectService.get(anyString())).thenReturn(getAwsProjectDTO());
+        when(billingService.getExploratoryBillingData(anyString(), anyString(), anyString(), anyListOf(String.class))).thenReturn(getReport());
+
+        List<ProjectInfrastructureInfo> actualUserResources = infoService.getUserResources(getUserInfo());
+
+        assertEquals("resources should be equal", getAwsProjectInfrastructureInfo(), actualUserResources);
+        verify(endpointService).getEndpoints();
+        verify(projectService).getUserProjects(getUserInfo(), Boolean.FALSE);
+        verify(expDAO).findExploratories(USER.toLowerCase(), PROJECT);
+        verify(billingService).getBillingProjectQuoteUsed(PROJECT);
+        verify(projectService).get(PROJECT);
+        verify(billingService).getExploratoryBillingData(PROJECT, ENDPOINT_NAME, EXPLORATORY_NAME, Collections.singletonList(COMPUTE_NAME));
+        verifyNoMoreInteractions(endpointService, projectService, expDAO, billingService);
+    }
+
+    @Test
+    public void getAzureUserResources() {
+        when(endpointService.getEndpoints()).thenReturn(Collections.singletonList(getEndpointDTO()));
+        when(projectService.getUserProjects(any(UserInfo.class), anyBoolean())).thenReturn(Collections.singletonList(getAzureProjectDTO()));
+        when(expDAO.findExploratories(anyString(), anyString())).thenReturn(getUserInstanceDTOs());
+        when(billingService.getBillingProjectQuoteUsed(anyString())).thenReturn(10);
+        when(projectService.get(anyString())).thenReturn(getAzureProjectDTO());
+        when(billingService.getExploratoryBillingData(anyString(), anyString(), anyString(), anyListOf(String.class))).thenReturn(getReport());
+
+        List<ProjectInfrastructureInfo> actualUserResources = infoService.getUserResources(getUserInfo());
+
+        assertEquals("resources should be equal", getAzureProjectInfrastructureInfo(), actualUserResources);
+        verify(endpointService).getEndpoints();
+        verify(projectService).getUserProjects(getUserInfo(), Boolean.FALSE);
+        verify(expDAO).findExploratories(USER.toLowerCase(), PROJECT);
+        verify(billingService).getBillingProjectQuoteUsed(PROJECT);
+        verify(projectService).get(PROJECT);
+        verify(billingService).getExploratoryBillingData(PROJECT, ENDPOINT_NAME, EXPLORATORY_NAME, Collections.singletonList(COMPUTE_NAME));
+        verifyNoMoreInteractions(endpointService, projectService, expDAO, billingService);
+    }
+
+    @Test
+    public void getGcpUserResources() {
+        when(endpointService.getEndpoints()).thenReturn(Collections.singletonList(getEndpointDTO()));
+        when(projectService.getUserProjects(any(UserInfo.class), anyBoolean())).thenReturn(Collections.singletonList(getGcpProjectDTO()));
+        when(expDAO.findExploratories(anyString(), anyString())).thenReturn(getUserInstanceDTOs());
+        when(billingService.getBillingProjectQuoteUsed(anyString())).thenReturn(10);
+        when(projectService.get(anyString())).thenReturn(getGcpProjectDTO());
+        when(billingService.getExploratoryBillingData(anyString(), anyString(), anyString(), anyListOf(String.class))).thenReturn(getReport());
+
+        List<ProjectInfrastructureInfo> actualUserResources = infoService.getUserResources(getUserInfo());
+
+        assertEquals("resources should be equal", getGcpProjectInfrastructureInfo(), actualUserResources);
+        verify(endpointService).getEndpoints();
+        verify(projectService).getUserProjects(getUserInfo(), Boolean.FALSE);
+        verify(expDAO).findExploratories(USER.toLowerCase(), PROJECT);
+        verify(billingService).getBillingProjectQuoteUsed(PROJECT);
+        verify(projectService).get(PROJECT);
+        verify(billingService).getExploratoryBillingData(PROJECT, ENDPOINT_NAME, EXPLORATORY_NAME, Collections.singletonList(COMPUTE_NAME));
+        verifyNoMoreInteractions(endpointService, projectService, expDAO, billingService);
+    }
+
+    @Test
+    public void getHeathStatus() {
+        when(configuration.isBillingSchedulerEnabled()).thenReturn(Boolean.TRUE);
+        when(configuration.isAuditEnabled()).thenReturn(Boolean.TRUE);
+        when(projectService.isAnyProjectAssigned(any(UserInfo.class))).thenReturn(Boolean.TRUE);
+
+        HealthStatusPageDTO actualHeathStatus = infoService.getHeathStatus(getUserInfo());
+
+        assertEquals("HealthStatusPageDTO should be equal", getHealthStatusPageDTO(), actualHeathStatus);
+        verify(projectService).isAnyProjectAssigned(getUserInfo());
+        verify(configuration).isBillingSchedulerEnabled();
+        verify(configuration).isAuditEnabled();
+        verifyNoMoreInteractions(configuration, projectService);
+    }
+
+    @Test
+    public void getInfrastructureMetaInfo() {
+        Manifests.DEFAULT.put("GIT-Branch", "branch");
+        Manifests.DEFAULT.put("GIT-Commit", "commit");
+        Manifests.DEFAULT.put("DataLab-Version", "version");
+
+        InfrastructureMetaInfoDTO actualInfrastructureMetaInfo = infoService.getInfrastructureMetaInfo();
+
+        assertEquals("InfrastructureMetaInfoDTO should be equal", getInfrastructureMetaInfoDTO(), actualInfrastructureMetaInfo);
+    }
+
+    private InfrastructureMetaInfoDTO getInfrastructureMetaInfoDTO() {
+        return InfrastructureMetaInfoDTO.builder()
+                .branch("branch")
+                .commit("commit")
+                .version("version")
+                .releaseNotes("https://github.com/apache/incubator-dlab/blob/branch/RELEASE_NOTES.md")
+                .build();
+    }
+
+    private HealthStatusPageDTO getHealthStatusPageDTO() {
+        return HealthStatusPageDTO.builder()
+                .status("ok")
+                .listResources(Collections.emptyList())
+                .billingEnabled(Boolean.TRUE)
+                .auditEnabled(Boolean.TRUE)
+                .projectAdmin(Boolean.FALSE)
+                .admin(Boolean.FALSE)
+                .projectAssigned(Boolean.TRUE)
+                .bucketBrowser(HealthStatusPageDTO.BucketBrowser.builder()
+                        .view(Boolean.TRUE)
+                        .upload(Boolean.TRUE)
+                        .download(Boolean.TRUE)
+                        .delete(Boolean.TRUE)
+                        .build())
+                .build();
+    }
+
+    private List<ProjectInfrastructureInfo> getProjectInfrastructureInfo() {
+        List<ProjectInfrastructureInfo> objects = new ArrayList<>();
+        objects.add(ProjectInfrastructureInfo.builder()
+                .project(PROJECT)
+                .billingQuoteUsed(10)
+                .shared(Collections.singletonMap(ENDPOINT_NAME, Collections.emptyMap()))
+                .exploratory(getUserInstanceDTOs())
+                .exploratoryBilling(Collections.singletonList(getReport()))
+                .endpoints(Collections.singletonList(getEndpointDTO()))
+                .build());
+        return objects;
+    }
+
+    private List<ProjectInfrastructureInfo> getAwsProjectInfrastructureInfo() {
+        List<ProjectInfrastructureInfo> objects = new ArrayList<>();
+        objects.add(ProjectInfrastructureInfo.builder()
+                .project(PROJECT)
+                .billingQuoteUsed(10)
+                .shared(Collections.singletonMap(ENDPOINT_NAME, getAwsEdgeInfo()))
+                .exploratory(getUserInstanceDTOs())
+                .exploratoryBilling(Collections.singletonList(getReport()))
+                .endpoints(Collections.singletonList(getEndpointDTO()))
+                .build());
+        return objects;
+    }
+
+    private List<ProjectInfrastructureInfo> getAzureProjectInfrastructureInfo() {
+        List<ProjectInfrastructureInfo> objects = new ArrayList<>();
+        objects.add(ProjectInfrastructureInfo.builder()
+                .project(PROJECT)
+                .billingQuoteUsed(10)
+                .shared(Collections.singletonMap(ENDPOINT_NAME, getAzureEdgeInfo()))
+                .exploratory(getUserInstanceDTOs())
+                .exploratoryBilling(Collections.singletonList(getReport()))
+                .endpoints(Collections.singletonList(getEndpointDTO()))
+                .build());
+        return objects;
+    }
+
+    private List<ProjectInfrastructureInfo> getGcpProjectInfrastructureInfo() {
+        List<ProjectInfrastructureInfo> objects = new ArrayList<>();
+        objects.add(ProjectInfrastructureInfo.builder()
+                .project(PROJECT)
+                .billingQuoteUsed(10)
+                .shared(Collections.singletonMap(ENDPOINT_NAME, getGcpEdgeInfo()))
+                .exploratory(getUserInstanceDTOs())
+                .exploratoryBilling(Collections.singletonList(getReport()))
+                .endpoints(Collections.singletonList(getEndpointDTO()))
+                .build());
+        return objects;
+    }
+
+    private Map<String, String> getAwsEdgeInfo() {
+        HashMap<String, String> edge = new HashMap<>();
+        edge.put("status", "running");
+        edge.put("edge_node_ip", "publicIp");
+        edge.put("user_own_bicket_name", "ownBucketName");
+        edge.put("shared_bucket_name", "sharedBucketName");
+        return edge;
+    }
+
+    private Map<String, String> getAzureEdgeInfo() {
+        HashMap<String, String> edge = new HashMap<>();
+        edge.put("status", "running");
+        edge.put("edge_node_ip", "publicIp");
+        edge.put("user_container_name", "userContainerName");
+        edge.put("shared_container_name", "sharedContainerName");
+        edge.put("user_storage_account_name", "userStorageAccountName");
+        edge.put("shared_storage_account_name", "sharedStorageAccountName");
+        edge.put("datalake_name", "dataLakeName");
+        edge.put("datalake_user_directory_name", "dataLakeDirectoryName");
+        edge.put("datalake_shared_directory_name", "dataLakeSharedDirectoryName");
+        return edge;
+    }
+
+    private Map<String, String> getGcpEdgeInfo() {
+        HashMap<String, String> edge = new HashMap<>();
+        edge.put("status", "running");
+        edge.put("edge_node_ip", "publicIp");
+        edge.put("user_own_bucket_name", "ownBucketName");
+        edge.put("shared_bucket_name", "sharedBucketName");
+        return edge;
+    }
+
+    private ProjectDTO getProjectDTO() {
+        return ProjectDTO.builder()
+                .name(PROJECT)
+                .endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, null)))
+                .build();
+    }
+
+    private ProjectDTO getAwsProjectDTO() {
+        EdgeInfoAws edgeInfoAws = new EdgeInfoAws();
+        edgeInfoAws.setPublicIp("publicIp");
+        edgeInfoAws.setUserOwnBucketName("ownBucketName");
+        edgeInfoAws.setSharedBucketName("sharedBucketName");
+
+        return ProjectDTO.builder()
+                .name(PROJECT)
+                .endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, edgeInfoAws)))
+                .build();
+    }
+
+    private ProjectDTO getAzureProjectDTO() {
+        EdgeInfoAzure edgeInfoAzure = new EdgeInfoAzure();
+        edgeInfoAzure.setPublicIp("publicIp");
+        edgeInfoAzure.setUserContainerName("userContainerName");
+        edgeInfoAzure.setSharedContainerName("sharedContainerName");
+        edgeInfoAzure.setUserStorageAccountName("userStorageAccountName");
+        edgeInfoAzure.setSharedStorageAccountName("sharedStorageAccountName");
+        edgeInfoAzure.setDataLakeName("dataLakeName");
+        edgeInfoAzure.setDataLakeDirectoryName("dataLakeDirectoryName");
+        edgeInfoAzure.setDataLakeSharedDirectoryName("dataLakeSharedDirectoryName");
+
+        return ProjectDTO.builder()
+                .name(PROJECT)
+                .endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, edgeInfoAzure)))
+                .build();
+    }
+
+    private ProjectDTO getGcpProjectDTO() {
+        EdgeInfoGcp edgeInfoGcp = new EdgeInfoGcp();
+        edgeInfoGcp.setPublicIp("publicIp");
+        edgeInfoGcp.setUserOwnBucketName("ownBucketName");
+        edgeInfoGcp.setSharedBucketName("sharedBucketName");
+
+        return ProjectDTO.builder()
+                .name(PROJECT)
+                .endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, edgeInfoGcp)))
+                .build();
+    }
+
+    private List<UserInstanceDTO> getUserInstanceDTOs() {
+        return Collections.singletonList(
+                new UserInstanceDTO().withUser(USER).withProject(PROJECT).withExploratoryName(EXPLORATORY_NAME).withEndpoint(ENDPOINT_NAME)
+                        .withResources(Collections.singletonList(getCompute()))
+        );
+    }
+
+    private UserComputationalResource getCompute() {
+        UserComputationalResource resource = new UserComputationalResource();
+        resource.setComputationalName(COMPUTE_NAME);
+        resource.setImageName(DataEngineType.SPARK_STANDALONE.getName());
+
+        return resource;
+    }
+
+    private BillingReport getReport() {
+        BillingReportLine line1 = BillingReportLine.builder().cost(1.0).user(USER).resourceType(BillingResourceType.EXPLORATORY).project(PROJECT).endpoint(ENDPOINT_NAME)
+                .resourceName(EXPLORATORY_NAME).currency(CURRENCY).build();
+        BillingReportLine line2 = BillingReportLine.builder().cost(1.0).user(USER).resourceType(BillingResourceType.COMPUTATIONAL).project(PROJECT).endpoint(ENDPOINT_NAME)
+                .resourceName(COMPUTE_NAME).exploratoryName(EXPLORATORY_NAME).currency(CURRENCY).build();
+        List<BillingReportLine> billingReportLines = Arrays.asList(line1, line2);
+
+        return BillingReport.builder()
+                .name(EXPLORATORY_NAME)
+                .reportLines(billingReportLines)
+                .totalCost(2.0)
+                .currency(CURRENCY)
+                .build();
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java
new file mode 100644
index 0000000..d68e157
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java
@@ -0,0 +1,226 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.datalab.backendapi.dao.ProjectDAO;
+import com.epam.datalab.backendapi.dao.SettingsDAO;
+import com.epam.datalab.backendapi.dao.UserGroupDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.base.computational.FullComputationalTemplate;
+import com.epam.datalab.dto.imagemetadata.ComputationalMetadataDTO;
+import com.epam.datalab.dto.imagemetadata.ComputationalResourceShapeDto;
+import com.epam.datalab.dto.imagemetadata.ExploratoryMetadataDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class InfrastructureTemplateServiceBaseTest {
+
+    @Mock
+    private SettingsDAO settingsDAO;
+    @Mock
+    private RESTService provisioningService;
+    @Mock
+    private ProjectDAO projectDAO;
+    @Mock
+    private EndpointService endpointService;
+    @Mock
+    private UserGroupDAO userGroupDao;
+    @Mock
+    private SelfServiceApplicationConfiguration configuration;
+
+    @InjectMocks
+    private InfrastructureTemplateServiceBaseChild infrastructureTemplateServiceBaseChild =
+            new InfrastructureTemplateServiceBaseChild();
+
+    @Test
+    public void getExploratoryTemplates() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        ExploratoryMetadataDTO emDto1 = new ExploratoryMetadataDTO("someImage1");
+        HashMap<String, List<ComputationalResourceShapeDto>> shapes1 = new HashMap<>();
+        shapes1.put("Memory optimized", Arrays.asList(
+                new ComputationalResourceShapeDto("Standard_E4s_v3", "someSize", "someDescription",
+                        "someRam", 2),
+                new ComputationalResourceShapeDto("Standard_E32s_v3", "someSize2", "someDescription2",
+                        "someRam2", 5)));
+        emDto1.setExploratoryEnvironmentShapes(shapes1);
+
+        ExploratoryMetadataDTO emDto2 = new ExploratoryMetadataDTO("someImage2");
+        HashMap<String, List<ComputationalResourceShapeDto>> shapes2 = new HashMap<>();
+        shapes2.put("Compute optimized", Arrays.asList(
+                new ComputationalResourceShapeDto("Standard_F2s", "someSize", "someDescription",
+                        "someRam", 3),
+                new ComputationalResourceShapeDto("Standard_F16s", "someSize2", "someDescription2",
+                        "someRam2", 6)));
+        emDto2.setExploratoryEnvironmentShapes(shapes2);
+        List<ExploratoryMetadataDTO> expectedEmdDtoList = Arrays.asList(emDto1, emDto2);
+        when(userGroupDao.getUserGroups(anyString())).thenReturn(Collections.emptySet());
+        when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(expectedEmdDtoList.toArray());
+        when(settingsDAO.getConfOsFamily()).thenReturn("someConfOsFamily");
+
+        UserInfo userInfo = new UserInfo("test", "token");
+        List<ExploratoryMetadataDTO> actualEmdDtoList =
+                infrastructureTemplateServiceBaseChild.getExploratoryTemplates(userInfo, "project", "endpoint");
+        assertNotNull(actualEmdDtoList);
+        assertEquals(expectedEmdDtoList, actualEmdDtoList);
+
+        verify(provisioningService).get(endpointDTO().getUrl() + "docker/exploratory", "token", ExploratoryMetadataDTO[].class);
+        verify(settingsDAO, times(2)).getConfOsFamily();
+        verify(userGroupDao).getUserGroups("test");
+        verifyNoMoreInteractions(provisioningService, settingsDAO, userGroupDao);
+    }
+
+    @Test
+    public void getExploratoryTemplatesWithException() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        doThrow(new DatalabException("Could not load list of exploratory templates for user"))
+                .when(provisioningService).get(anyString(), anyString(), any(Class.class));
+
+        UserInfo userInfo = new UserInfo("test", "token");
+        try {
+            infrastructureTemplateServiceBaseChild.getExploratoryTemplates(userInfo, "project", "endpoint");
+        } catch (DatalabException e) {
+            assertEquals("Could not load list of exploratory templates for user", e.getMessage());
+        }
+        verify(provisioningService).get(endpointDTO().getUrl() + "docker/exploratory", "token", ExploratoryMetadataDTO[].class);
+        verifyNoMoreInteractions(provisioningService);
+    }
+
+    @Test
+    public void getComputationalTemplates() throws NoSuchFieldException, IllegalAccessException {
+
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        final ComputationalMetadataDTO computationalMetadataDTO = new ComputationalMetadataDTO("dataengine-service");
+        computationalMetadataDTO.setComputationResourceShapes(Collections.emptyMap());
+        List<ComputationalMetadataDTO> expectedCmdDtoList = Collections.singletonList(
+                computationalMetadataDTO
+        );
+        when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
+                null, null, null, null, true)));
+        when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(expectedCmdDtoList.toArray(new ComputationalMetadataDTO[]{}));
+
+        List<FullComputationalTemplate> expectedFullCmdDtoList = expectedCmdDtoList.stream()
+                .map(e -> infrastructureTemplateServiceBaseChild.getCloudFullComputationalTemplate(e))
+                .collect(Collectors.toList());
+
+        UserInfo userInfo = new UserInfo("test", "token");
+        List<FullComputationalTemplate> actualFullCmdDtoList =
+                infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project", "endpoint");
+        assertNotNull(actualFullCmdDtoList);
+        assertEquals(expectedFullCmdDtoList.size(), actualFullCmdDtoList.size());
+        for (int i = 0; i < expectedFullCmdDtoList.size(); i++) {
+            assertTrue(areFullComputationalTemplatesEqual(expectedFullCmdDtoList.get(i), actualFullCmdDtoList.get(i)));
+        }
+
+        verify(provisioningService).get(endpointDTO().getUrl() + "docker/computational", "token", ComputationalMetadataDTO[].class);
+        verifyNoMoreInteractions(provisioningService);
+    }
+
+    @Test
+    public void getComputationalTemplatesWhenMethodThrowsException() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        doThrow(new DatalabException("Could not load list of computational templates for user"))
+                .when(provisioningService).get(anyString(), anyString(), any(Class.class));
+
+        UserInfo userInfo = new UserInfo("test", "token");
+        try {
+            infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project", "endpoint");
+        } catch (DatalabException e) {
+            assertEquals("Could not load list of computational templates for user", e.getMessage());
+        }
+        verify(provisioningService).get(endpointDTO().getUrl() + "docker/computational", "token",
+                ComputationalMetadataDTO[].class);
+        verifyNoMoreInteractions(provisioningService);
+    }
+
+    @Test
+    public void getComputationalTemplatesWithInapproprietaryImageName() {
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        final ComputationalMetadataDTO computationalMetadataDTO = new ComputationalMetadataDTO("dataengine-service");
+        computationalMetadataDTO.setComputationResourceShapes(Collections.emptyMap());
+        List<ComputationalMetadataDTO> expectedCmdDtoList = Collections.singletonList(computationalMetadataDTO);
+        when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(expectedCmdDtoList.toArray(new ComputationalMetadataDTO[]{}));
+        when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
+                null, null, null, null, true)));
+        when(configuration.getMinEmrInstanceCount()).thenReturn(1);
+        when(configuration.getMaxEmrInstanceCount()).thenReturn(2);
+        when(configuration.getMaxEmrSpotInstanceBidPct()).thenReturn(3);
+        when(configuration.getMinEmrSpotInstanceBidPct()).thenReturn(4);
+
+        UserInfo userInfo = new UserInfo("test", "token");
+        try {
+            infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project", "endpoint");
+        } catch (IllegalArgumentException e) {
+            assertEquals("Unknown data engine null", e.getMessage());
+        }
+        verify(provisioningService).get(endpointDTO().getUrl() + "docker/computational", "token", ComputationalMetadataDTO[].class);
+        verifyNoMoreInteractions(provisioningService);
+    }
+
+    private boolean areFullComputationalTemplatesEqual(FullComputationalTemplate object1,
+                                                       FullComputationalTemplate object2) throws NoSuchFieldException,
+            IllegalAccessException {
+        Field computationalMetadataDTO1 = object1.getClass().getDeclaredField("computationalMetadataDTO");
+        computationalMetadataDTO1.setAccessible(true);
+        Field computationalMetadataDTO2 = object2.getClass().getSuperclass().getDeclaredField("computationalMetadataDTO");
+        computationalMetadataDTO2.setAccessible(true);
+        return computationalMetadataDTO1.get(object1).equals(computationalMetadataDTO2.get(object2));
+    }
+
+    private EndpointDTO endpointDTO() {
+        return new EndpointDTO("test", "url", "", null, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
+    }
+
+    private class InfrastructureTemplateServiceBaseChild extends InfrastructureTemplateServiceImpl {
+
+        protected FullComputationalTemplate getCloudFullComputationalTemplate(ComputationalMetadataDTO metadataDTO) {
+            return new FullComputationalTemplate(metadataDTO);
+        }
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/LibraryServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/LibraryServiceImplTest.java
new file mode 100644
index 0000000..80c0327
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/LibraryServiceImplTest.java
@@ -0,0 +1,490 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryLibDAO;
+import com.epam.datalab.backendapi.domain.EndpointDTO;
+import com.epam.datalab.backendapi.domain.NotebookTemplate;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.resources.dto.LibInfoRecord;
+import com.epam.datalab.backendapi.resources.dto.LibInstallFormDTO;
+import com.epam.datalab.backendapi.resources.dto.LibKey;
+import com.epam.datalab.backendapi.resources.dto.LibraryStatus;
+import com.epam.datalab.backendapi.service.EndpointService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.dto.exploratory.LibInstallDTO;
+import com.epam.datalab.dto.exploratory.LibStatus;
+import com.epam.datalab.dto.exploratory.LibraryInstallDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.model.library.Library;
+import com.epam.datalab.rest.client.RESTService;
+import org.bson.Document;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyListOf;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LibraryServiceImplTest {
+
+    private static final String LIB_NAME = "name";
+    private static final String LIB_GROUP = "group";
+    private static final String LIB_VERSION = "version";
+    private static final String UUID = "id";
+    private final String USER = "test";
+    private final String EXPLORATORY_NAME = "explName";
+    private final String PROJECT = "projectName";
+    private final String COMPUTATIONAL_NAME = "compName";
+
+    private static final String GROUP_JAVA = "java";
+    private static final String GROUP_PIP2 = "pip2";
+    private static final String GROUP_PIP3 = "pip3";
+    private static final String GROUP_R_PKG = "r_pkg";
+    private static final String GROUP_OS_PKG = "os_pkg";
+    private static final String GROUP_OTHERS = "others";
+
+    private LibInstallDTO liDto;
+    private List<LibInstallDTO> libs;
+    private LibInstallFormDTO libInstallFormDTO;
+    private LibraryInstallDTO libraryInstallDto;
+
+    @Mock
+    private ExploratoryDAO exploratoryDAO;
+    @Mock
+    private ExploratoryLibDAO libraryDAO;
+    @Mock
+    private RequestBuilder requestBuilder;
+    @Mock
+    private RequestId requestId;
+    @Mock
+    private RESTService provisioningService;
+    @Mock
+    private EndpointService endpointService;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @InjectMocks
+    private LibraryServiceImpl libraryService;
+
+    @Before
+    public void setUp() {
+        prepareForTesting();
+    }
+
+    @Test
+    public void testGetLibs() {
+        Document document = new Document();
+        when(libraryDAO.findExploratoryLibraries(anyString(), anyString(), anyString())).thenReturn(document);
+
+        List<Document> expectedList = new ArrayList<>();
+        List<Document> actualList = libraryService.getLibs(USER, PROJECT, EXPLORATORY_NAME, "");
+        assertNotNull(actualList);
+        assertEquals(expectedList, actualList);
+
+        verify(libraryDAO).findExploratoryLibraries(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(libraryDAO);
+    }
+
+    @Test
+    public void getLibInfo() {
+        Document document = new Document();
+        when(libraryDAO.findAllLibraries(anyString(), anyString(), anyString())).thenReturn(document);
+
+        List<LibInfoRecord> expectedList = new ArrayList<>();
+        List<LibInfoRecord> actualList = libraryService.getLibInfo(USER, PROJECT, EXPLORATORY_NAME);
+        assertNotNull(actualList);
+        assertEquals(expectedList, actualList);
+
+        verify(libraryDAO).findAllLibraries(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(libraryDAO);
+    }
+
+    @Test
+    public void getLibInfoWhenListsOfExploratoryAndComputationalLibsAreNotEmpty() {
+        when(libraryDAO.findAllLibraries(anyString(), anyString(), anyString()))
+                .thenReturn(getDocumentWithExploratoryAndComputationalLibs());
+
+        List<LibInfoRecord> expectedList = getLibInfoRecordList();
+        List<LibInfoRecord> actualList = libraryService.getLibInfo(USER, PROJECT, EXPLORATORY_NAME);
+        assertNotNull(actualList);
+        assertEquals(expectedList, actualList);
+
+        verify(libraryDAO).findAllLibraries(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(libraryDAO);
+    }
+
+    @Test
+    public void installComputationalLibsWithoutOverride() {
+        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
+        final List<LibInstallDTO> libsToInstall = getLibs("installing");
+        libraryInstallDTO.setLibs(libsToInstall);
+        final UserInfo user = getUser();
+
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
+        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
+        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class),
+                any(UserComputationalResource.class), anyListOf(LibInstallDTO.class), any(EndpointDTO.class))).thenReturn(libraryInstallDTO);
+
+
+        final String uuid = libraryService.installComputationalLibs(user, PROJECT, EXPLORATORY_NAME,
+                COMPUTATIONAL_NAME, getLibs(null), null);
+
+        assertEquals(UUID, uuid);
+
+        verify(libraryDAO).getLibrary(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME, LIB_GROUP, LIB_NAME);
+        verify(requestBuilder).newLibInstall(refEq(user), refEq(getUserInstanceDto()),
+                refEq(getUserComputationalResourceWithName(COMPUTATIONAL_NAME)), eq(libsToInstall), refEq(endpointDTO()));
+        verify(provisioningService).post(eq(endpointDTO().getUrl() + "library/computational/lib_install"), eq(user.getAccessToken()),
+                refEq(libraryInstallDTO), eq(String.class));
+        verify(libraryDAO).addLibrary(eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME),
+                eq(COMPUTATIONAL_NAME), refEq(libsToInstall.get(0)), eq(false));
+        verify(requestId).put(user.getName(), UUID);
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
+        verifyNoMoreInteractions(libraryDAO, requestBuilder, provisioningService, requestId, exploratoryDAO);
+    }
+
+    @Test
+    public void installComputationalLibsWhenComputationalNotFound() {
+        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
+        final List<LibInstallDTO> libsToInstall = getLibs("installing");
+        libraryInstallDTO.setLibs(libsToInstall);
+        libraryInstallDTO.setProject(PROJECT);
+        final UserInfo user = getUser();
+
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
+        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
+        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class),
+                any(UserComputationalResource.class), anyListOf(LibInstallDTO.class), any(EndpointDTO.class)))
+                .thenReturn(libraryInstallDTO);
+
+
+        expectedException.expect(DatalabException.class);
+        expectedException.expectMessage("Computational with name " + COMPUTATIONAL_NAME + "X was not found");
+
+        libraryService.installComputationalLibs(user, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME + "X", getLibs(null), null);
+    }
+
+    @Test
+    public void installComputationalLibsWithOverride() {
+        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
+        final List<LibInstallDTO> libsToInstall = getLibs("installing");
+        libraryInstallDTO.setProject(PROJECT);
+        libraryInstallDTO.setLibs(libsToInstall);
+        final UserInfo user = getUser();
+
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
+        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
+        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class),
+                any(UserComputationalResource.class), anyListOf(LibInstallDTO.class), any(EndpointDTO.class)))
+                .thenReturn(libraryInstallDTO);
+        when(libraryDAO.getLibrary(anyString(), anyString(), anyString(), anyString(), anyString(), anyString())).thenReturn(getLibrary(LibStatus.INSTALLED));
+
+        final String uuid = libraryService.installComputationalLibs(user, PROJECT, EXPLORATORY_NAME,
+                COMPUTATIONAL_NAME, getLibs(null), null);
+
+        assertEquals(UUID, uuid);
+
+        libsToInstall.get(0).setOverride(true);
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
+        verify(libraryDAO).getLibrary(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME, LIB_GROUP, LIB_NAME);
+        verify(libraryDAO).addLibrary(eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME),
+                eq(COMPUTATIONAL_NAME), refEq(libsToInstall.get(0)), eq(true));
+        verify(requestBuilder).newLibInstall(refEq(user), refEq(getUserInstanceDto()),
+                refEq(getUserComputationalResourceWithName(COMPUTATIONAL_NAME)), eq(libsToInstall), refEq(endpointDTO()));
+        verify(provisioningService).post(eq(endpointDTO().getUrl() + "library/computational/lib_install"),
+                eq(user.getAccessToken()),
+                refEq(libraryInstallDTO), eq(String.class));
+        verify(requestId).put(user.getName(), UUID);
+        verifyNoMoreInteractions(libraryDAO, requestBuilder, provisioningService, requestId, exploratoryDAO);
+
+    }
+
+
+    @Test
+    public void installComputationalLibsWhenLibraryIsAlreadyInstalling() {
+        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
+        final List<LibInstallDTO> libsToInstall = getLibs("installing");
+        libraryInstallDTO.setLibs(libsToInstall);
+        final UserInfo user = getUser();
+
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
+        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
+        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class),
+                any(UserComputationalResource.class), anyListOf(LibInstallDTO.class), any(EndpointDTO.class)))
+                .thenReturn(libraryInstallDTO);
+        when(libraryDAO.getLibrary(anyString(), anyString(), anyString(), anyString(), anyString(), anyString())).thenReturn(getLibrary(LibStatus.INSTALLING));
+
+        try {
+            libraryService.installComputationalLibs(user, PROJECT, EXPLORATORY_NAME,
+                    COMPUTATIONAL_NAME, getLibs(null), null);
+        } catch (DatalabException e) {
+            assertEquals("Library name is already installing", e.getMessage());
+        }
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
+        verify(libraryDAO).getLibrary(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME, LIB_GROUP, LIB_NAME);
+        verifyNoMoreInteractions(libraryDAO, requestBuilder, provisioningService, requestId, exploratoryDAO);
+    }
+
+    @Test
+    public void installExploratoryLibsWithoutOverride() {
+        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
+        final List<LibInstallDTO> libsToInstall = getLibs("installing");
+        libraryInstallDTO.setLibs(libsToInstall);
+        final UserInfo user = getUser();
+
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
+        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
+        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class), any(EndpointDTO.class),
+                anyListOf(LibInstallDTO.class))).thenReturn(libraryInstallDTO);
+
+
+        final String uuid = libraryService.installExploratoryLibs(user, PROJECT, EXPLORATORY_NAME, getLibs(null), null);
+
+        assertEquals(UUID, uuid);
+
+        verify(libraryDAO).getLibrary(USER, PROJECT, EXPLORATORY_NAME, LIB_GROUP, LIB_NAME);
+        verify(requestBuilder).newLibInstall(refEq(user), refEq(getUserInstanceDto()), eq(endpointDTO()), eq(libsToInstall));
+        verify(provisioningService).post(eq(endpointDTO().getUrl() + "library/exploratory/lib_install"), eq(user.getAccessToken()),
+                refEq(libraryInstallDTO), eq(String.class));
+        verify(libraryDAO).addLibrary(eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME), refEq(libsToInstall.get(0)), eq(false));
+        verify(requestId).put(user.getName(), UUID);
+        verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(libraryDAO, requestBuilder, provisioningService, requestId, exploratoryDAO);
+    }
+
+    @Test
+    public void installExploratoryLibsWithOverride() {
+        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
+        final List<LibInstallDTO> libsToInstall = getLibs("installing");
+        libraryInstallDTO.setLibs(libsToInstall);
+        final UserInfo user = getUser();
+
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
+        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
+        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class), any(EndpointDTO.class),
+                anyListOf(LibInstallDTO.class))).thenReturn(libraryInstallDTO);
+        when(libraryDAO.getLibrary(anyString(), anyString(), anyString(), anyString(), anyString())).thenReturn(getLibrary(LibStatus.INSTALLED));
+
+        final String uuid = libraryService.installExploratoryLibs(user, PROJECT, EXPLORATORY_NAME, getLibs(null), null);
+
+        assertEquals(UUID, uuid);
+
+        libsToInstall.get(0).setOverride(true);
+        verify(libraryDAO).getLibrary(USER, PROJECT, EXPLORATORY_NAME, LIB_GROUP, LIB_NAME);
+        verify(libraryDAO).addLibrary(eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME), refEq(libsToInstall.get(0)), eq(true));
+        verify(requestBuilder).newLibInstall(refEq(user), refEq(getUserInstanceDto()), eq(endpointDTO()), eq(libsToInstall));
+        verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(provisioningService).post(eq(endpointDTO().getUrl() + "library/exploratory/lib_install"), eq(user.getAccessToken()),
+                refEq(libraryInstallDTO), eq(String.class));
+        verify(requestId).put(USER, uuid);
+        verifyNoMoreInteractions(libraryDAO, requestBuilder, provisioningService, requestId, exploratoryDAO);
+    }
+
+    @Test
+    public void installExploratoryLibsWhenLibIsAlreadyInstalling() {
+        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
+        final List<LibInstallDTO> libsToInstall = getLibs("installing");
+        libraryInstallDTO.setLibs(libsToInstall);
+        final UserInfo user = getUser();
+
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
+        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
+        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class), any(EndpointDTO.class),
+                anyListOf(LibInstallDTO.class))).thenReturn(libraryInstallDTO);
+        when(libraryDAO.getLibrary(anyString(), anyString(), anyString(), anyString(), anyString())).thenReturn(getLibrary(LibStatus.INSTALLING));
+
+        try {
+            libraryService.installExploratoryLibs(user, PROJECT, EXPLORATORY_NAME, getLibs(null), null);
+        } catch (DatalabException e) {
+            assertEquals("Library name is already installing", e.getMessage());
+        }
+
+        verify(libraryDAO).getLibrary(USER, PROJECT, EXPLORATORY_NAME, LIB_GROUP, LIB_NAME);
+        verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(libraryDAO, requestBuilder, provisioningService, requestId, exploratoryDAO);
+
+    }
+
+    @Test
+    public void getComputeLibGroups() {
+        List<Object> computeGroups = Arrays.asList(GROUP_PIP3, GROUP_OTHERS, GROUP_R_PKG, GROUP_OS_PKG, GROUP_JAVA);
+
+        List<String> computeGroupsResult = libraryService.getComputeLibGroups();
+
+        assertEquals("lists are not equal", computeGroups, computeGroupsResult);
+    }
+
+    @Test
+    public void getExploratoryJupyterLibGroups() {
+        List<Object> exploratoryGroups = Arrays.asList(GROUP_PIP2, GROUP_PIP3, GROUP_OTHERS, GROUP_OS_PKG, GROUP_R_PKG, GROUP_JAVA);
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(getJupyterUserInstanceDtoForLibGroups());
+
+        List<String> exploratoryGroupsResult = libraryService.getExploratoryLibGroups(getUser(), PROJECT, EXPLORATORY_NAME);
+
+        assertEquals("lists are not equal", exploratoryGroups, exploratoryGroupsResult);
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+    }
+
+    @Test
+    public void getExploratoryRstudioLibGroups() {
+        List<Object> exploratoryGroups = Arrays.asList(GROUP_PIP2, GROUP_PIP3, GROUP_OTHERS, GROUP_OS_PKG, GROUP_R_PKG);
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(getRstudioUserInstanceDtoForLibGroups());
+
+        List<String> exploratoryGroupsResult = libraryService.getExploratoryLibGroups(getUser(), PROJECT, EXPLORATORY_NAME);
+
+        assertEquals("lists are not equal", exploratoryGroups, exploratoryGroupsResult);
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+    }
+
+    private Library getLibrary(LibStatus status) {
+        return new Library(LIB_GROUP, LIB_NAME, "1", status, "");
+    }
+
+    private List<LibInstallDTO> getLibs(String status) {
+        final LibInstallDTO libInstallDTO = new LibInstallDTO(LIB_GROUP, LIB_NAME, LIB_VERSION);
+        libInstallDTO.setStatus(status);
+        return Collections.singletonList(libInstallDTO);
+    }
+
+    private UserInfo getUser() {
+        return new UserInfo(USER, "token123");
+    }
+
+    private void prepareForTesting() {
+        liDto = new LibInstallDTO("someGroup", "someName", "someVersion");
+        libs = Collections.singletonList(liDto);
+        libInstallFormDTO = new LibInstallFormDTO();
+        libInstallFormDTO.setNotebookName(EXPLORATORY_NAME);
+        libInstallFormDTO.setComputationalName(COMPUTATIONAL_NAME);
+        libInstallFormDTO.setLibs(libs);
+        libraryInstallDto = new LibraryInstallDTO().withExploratoryName(EXPLORATORY_NAME)
+                .withComputationalName(COMPUTATIONAL_NAME).withApplicationName("");
+        libraryInstallDto.setLibs(new ArrayList<>());
+    }
+
+    private UserComputationalResource getUserComputationalResourceWithName(String name) {
+        UserComputationalResource resource = new UserComputationalResource();
+        resource.setComputationalName(name);
+        resource.setComputationalId("someId");
+        resource.setImageName("someImageName");
+        return resource;
+    }
+
+    private UserInstanceDTO getUserInstanceDto() {
+        final UserInstanceDTO userInstanceDTO = new UserInstanceDTO().withUser(USER).withExploratoryName(EXPLORATORY_NAME);
+        userInstanceDTO.getResources().add(getUserComputationalResourceWithName(COMPUTATIONAL_NAME));
+        return userInstanceDTO;
+    }
+
+    private UserInstanceDTO getJupyterUserInstanceDtoForLibGroups() {
+        return new UserInstanceDTO()
+                .withUser(USER)
+                .withExploratoryName(EXPLORATORY_NAME)
+                .withTemplateName(NotebookTemplate.JUPYTER.getName());
+    }
+
+    private UserInstanceDTO getRstudioUserInstanceDtoForLibGroups() {
+        return new UserInstanceDTO()
+                .withUser(USER)
+                .withExploratoryName(EXPLORATORY_NAME)
+                .withTemplateName(NotebookTemplate.RSTUDIO.getName());
+    }
+
+    private List<Document> getExpLibsList() {
+        Document explLibsDoc = new Document();
+        explLibsDoc.append(ExploratoryLibDAO.LIB_NAME, "expLibName");
+        explLibsDoc.append(ExploratoryLibDAO.LIB_VERSION, "expLibVersion");
+        explLibsDoc.append(ExploratoryLibDAO.LIB_GROUP, "expLibGroup");
+        explLibsDoc.append(ExploratoryLibDAO.STATUS, "expLibStatus");
+        explLibsDoc.append(ExploratoryLibDAO.ERROR_MESSAGE, "expLibErrorMessage");
+        return Collections.singletonList(explLibsDoc);
+    }
+
+    private Document getCompLibs() {
+        Document compLibs = new Document();
+        compLibs.append(ExploratoryLibDAO.LIB_NAME, "compLibName");
+        compLibs.append(ExploratoryLibDAO.LIB_VERSION, "compLibVersion");
+        compLibs.append(ExploratoryLibDAO.LIB_GROUP, "compLibGroup");
+        compLibs.append(ExploratoryLibDAO.STATUS, "compLibStatus");
+        compLibs.append(ExploratoryLibDAO.ERROR_MESSAGE, "compLibErrorMessage");
+
+        Document compResourcesAndLibs = new Document();
+        compResourcesAndLibs.append("compName", Collections.singletonList(compLibs));
+        return compResourcesAndLibs;
+    }
+
+    private Document getDocumentWithExploratoryAndComputationalLibs() {
+        return new Document().append(ExploratoryLibDAO.EXPLORATORY_LIBS, getExpLibsList())
+                .append(ExploratoryLibDAO.COMPUTATIONAL_LIBS, getCompLibs());
+    }
+
+    private List<LibInfoRecord> getLibInfoRecordList() {
+        LibKey explLibKey = new LibKey("expLibName", "expLibVersion", "expLibGroup");
+        List<LibraryStatus> explLibStatuses = Collections.singletonList(
+                new LibraryStatus(EXPLORATORY_NAME, "notebook", "expLibStatus", "expLibErrorMessage", null, null));
+
+        LibKey compLibKey = new LibKey("compLibName", "compLibVersion", "compLibGroup");
+        List<LibraryStatus> compLibStatuses = Collections.singletonList(
+                new LibraryStatus("compName", "cluster", "compLibStatus", "compLibErrorMessage", null, null));
+
+        return Arrays.asList(
+                new LibInfoRecord(compLibKey, compLibStatuses),
+                new LibInfoRecord(explLibKey, explLibStatuses)
+        );
+    }
+
+    private EndpointDTO endpointDTO() {
+        return new EndpointDTO("test", "url", "", null, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
+    }
+
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/MavenCentralLibraryServiceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/MavenCentralLibraryServiceTest.java
new file mode 100644
index 0000000..0141dcc
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/MavenCentralLibraryServiceTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.domain.MavenSearchArtifactResponse;
+import com.epam.datalab.backendapi.resources.dto.LibraryDTO;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.rest.client.RESTService;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.net.URI;
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.refEq;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MavenCentralLibraryServiceTest {
+
+    @Mock
+    private RESTService client;
+    @InjectMocks
+    private MavenCentralLibraryService mavenCentralLibraryService;
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void getLibraryId() {
+        when(client.get(any(URI.class), any())).thenReturn(getMavenResponse());
+
+        final LibraryDTO libDTO = mavenCentralLibraryService.getLibrary("groupId", "artifactId", "version");
+
+        assertNotNull(libDTO);
+        assertEquals("groupId:artifactId", libDTO.getName());
+        assertEquals("version", libDTO.getVersion());
+
+        verify(client).get(refEq(URI.create("/solrsearch/select?q=a:%22artifactId%22+AND+g" +
+                        ":%22groupId%22+AND+v:%22version%22+AND+(p:%22jar%22%20OR%20p:%22bundle%22)" +
+                        "&rows=20&wt=json&core=gav&p=jar")),
+                eq(MavenSearchArtifactResponse.class));
+    }
+
+    @Test
+    public void getLibraryIdWithException() {
+        when(client.get(any(URI.class), any())).thenThrow(new DatalabException("Can not get artifact info from maven " +
+                "central due to: Exception"));
+
+        expectedException.expect(DatalabException.class);
+        expectedException.expectMessage("Can not get artifact info from maven central due to: Exception");
+
+        mavenCentralLibraryService.getLibrary("groupId", "artifactId", "version");
+    }
+
+    private MavenSearchArtifactResponse getMavenResponse() {
+        final MavenSearchArtifactResponse response = new MavenSearchArtifactResponse();
+        MavenSearchArtifactResponse.Response.Artifact artifact = new MavenSearchArtifactResponse.Response.Artifact();
+        artifact.setId("test.group:artifact:1.0");
+        artifact.setVersion("1.0");
+        final MavenSearchArtifactResponse.Response rsp = new MavenSearchArtifactResponse.Response();
+        rsp.setArtifacts(Collections.singletonList(artifact));
+        response.setResponse(rsp);
+        return response;
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ReuploadKeyServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ReuploadKeyServiceImplTest.java
new file mode 100644
index 0000000..2044c9a
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ReuploadKeyServiceImplTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.ComputationalDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.domain.RequestId;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.util.RequestBuilder;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyCallbackDTO;
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyStatus;
+import com.epam.datalab.dto.reuploadkey.ReuploadKeyStatusDTO;
+import com.epam.datalab.model.ResourceData;
+import com.epam.datalab.model.ResourceType;
+import com.epam.datalab.rest.client.RESTService;
+import com.mongodb.client.result.UpdateResult;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static com.epam.datalab.dto.UserInstanceStatus.RUNNING;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ReuploadKeyServiceImplTest {
+
+    private final String USER = "test";
+    private final String TOKEN = "token";
+    private final String EXPLORATORY_NAME = "explName";
+
+    private UserInfo userInfo;
+
+    @Mock
+    private RESTService provisioningService;
+    @Mock
+    private RequestBuilder requestBuilder;
+    @Mock
+    private RequestId requestId;
+    @Mock
+    private ExploratoryService exploratoryService;
+    @Mock
+    private ComputationalDAO computationalDAO;
+    @Mock
+    private ExploratoryDAO exploratoryDAO;
+
+    @InjectMocks
+    private ReuploadKeyServiceImpl reuploadKeyService;
+
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Before
+    public void setUp() {
+        userInfo = getUserInfo();
+    }
+
+    @Test
+    public void updateResourceDataForEdgeWhenStatusCompleted() {
+        ResourceData resource = new ResourceData(ResourceType.EDGE, "someId", null, null);
+        ReuploadKeyStatusDTO dto = getReuploadKeyStatusDTO(resource, ReuploadKeyStatus.COMPLETED);
+
+        reuploadKeyService.updateResourceData(dto);
+
+        verifyZeroInteractions(exploratoryDAO, computationalDAO);
+    }
+
+    @Test
+    public void updateResourceDataForEdgeWhenStatusFailed() {
+        ResourceData resource = new ResourceData(ResourceType.EDGE, "someId", null, null);
+
+        ReuploadKeyStatusDTO dto = getReuploadKeyStatusDTO(resource, ReuploadKeyStatus.FAILED);
+        reuploadKeyService.updateResourceData(dto);
+
+        verifyZeroInteractions(exploratoryDAO, computationalDAO);
+    }
+
+    @Test
+    public void updateResourceDataForExploratoryWhenStatusCompleted() {
+        ResourceData resource = new ResourceData(ResourceType.EXPLORATORY, "someId", EXPLORATORY_NAME, null);
+        when(exploratoryDAO.updateStatusForExploratory(anyString(), anyString(), anyString(),
+                any(UserInstanceStatus.class))).thenReturn(mock(UpdateResult.class));
+        doNothing().when(exploratoryDAO).updateReuploadKeyForExploratory(anyString(), anyString(), anyString(), anyBoolean());
+
+        ReuploadKeyStatusDTO dto = getReuploadKeyStatusDTO(resource, ReuploadKeyStatus.COMPLETED);
+
+        reuploadKeyService.updateResourceData(dto);
+
+        verify(exploratoryDAO).updateStatusForExploratory(USER, null, EXPLORATORY_NAME, RUNNING);
+        verify(exploratoryDAO).updateReuploadKeyForExploratory(USER, null, EXPLORATORY_NAME, false);
+        verifyNoMoreInteractions(exploratoryDAO);
+        verifyZeroInteractions(computationalDAO);
+    }
+
+    @Test
+    public void updateResourceDataForExploratoryWhenStatusFailed() {
+        ResourceData resource = new ResourceData(ResourceType.EXPLORATORY, "someId", EXPLORATORY_NAME, null);
+        when(exploratoryDAO.updateStatusForExploratory(anyString(), anyString(), anyString(),
+                any(UserInstanceStatus.class))).thenReturn(mock(UpdateResult.class));
+
+        ReuploadKeyStatusDTO dto = getReuploadKeyStatusDTO(resource, ReuploadKeyStatus.FAILED);
+
+        reuploadKeyService.updateResourceData(dto);
+
+        verify(exploratoryDAO).updateStatusForExploratory(USER, null, EXPLORATORY_NAME, RUNNING);
+        verifyNoMoreInteractions(exploratoryDAO);
+        verifyZeroInteractions(computationalDAO);
+    }
+
+    @Test
+    public void updateResourceDataForClusterWhenStatusCompleted() {
+        ResourceData resource = new ResourceData(ResourceType.COMPUTATIONAL, "someId", EXPLORATORY_NAME, "compName");
+        doNothing().when(computationalDAO).updateStatusForComputationalResource(anyString(), anyString(), anyString(),
+                anyString(), any(UserInstanceStatus.class));
+        doNothing().when(computationalDAO).updateReuploadKeyFlagForComputationalResource(anyString(), anyString(),
+                anyString(), anyString(), anyBoolean());
+        ReuploadKeyStatusDTO dto = getReuploadKeyStatusDTO(resource, ReuploadKeyStatus.COMPLETED);
+
+        reuploadKeyService.updateResourceData(dto);
+
+        verify(computationalDAO).updateStatusForComputationalResource(USER, null, EXPLORATORY_NAME, "compName", RUNNING);
+        verify(computationalDAO).updateReuploadKeyFlagForComputationalResource(USER, null, EXPLORATORY_NAME,
+                "compName", false);
+        verifyNoMoreInteractions(computationalDAO);
+        verifyZeroInteractions(exploratoryDAO);
+    }
+
+    @Test
+    public void updateResourceDataForClusterWhenStatusFailed() {
+        ResourceData resource = new ResourceData(ResourceType.COMPUTATIONAL, "someId", EXPLORATORY_NAME, "compName");
+        doNothing().when(computationalDAO).updateStatusForComputationalResource(anyString(), anyString(), anyString(),
+                anyString(), any(UserInstanceStatus.class));
+        ReuploadKeyStatusDTO dto = getReuploadKeyStatusDTO(resource, ReuploadKeyStatus.FAILED);
+
+        reuploadKeyService.updateResourceData(dto);
+
+        verify(computationalDAO).updateStatusForComputationalResource(USER, null, EXPLORATORY_NAME, "compName", RUNNING);
+        verifyNoMoreInteractions(computationalDAO);
+        verifyZeroInteractions(exploratoryDAO);
+    }
+
+    private UserInfo getUserInfo() {
+        return new UserInfo(USER, TOKEN);
+    }
+
+    private ReuploadKeyStatusDTO getReuploadKeyStatusDTO(ResourceData resource, ReuploadKeyStatus status) {
+        return new ReuploadKeyStatusDTO().withReuploadKeyCallbackDto(
+                new ReuploadKeyCallbackDTO().withResource(resource)).withReuploadKeyStatus(status).withUser(USER);
+    }
+
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/SchedulerJobServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/SchedulerJobServiceImplTest.java
new file mode 100644
index 0000000..98fa750
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/SchedulerJobServiceImplTest.java
@@ -0,0 +1,1125 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.ComputationalDAO;
+import com.epam.datalab.backendapi.dao.ExploratoryDAO;
+import com.epam.datalab.backendapi.dao.SchedulerJobDAO;
+import com.epam.datalab.backendapi.service.ComputationalService;
+import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.SecurityService;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.dto.UserInstanceDTO;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.dto.aws.computational.AwsComputationalResource;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.epam.datalab.exceptions.ResourceInappropriateStateException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import com.epam.datalab.model.scheduler.SchedulerJobData;
+import com.mongodb.client.result.UpdateResult;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static com.epam.datalab.dto.UserInstanceStatus.RUNNING;
+import static com.epam.datalab.dto.UserInstanceStatus.STARTING;
+import static com.epam.datalab.dto.UserInstanceStatus.STOPPED;
+import static com.epam.datalab.dto.UserInstanceStatus.STOPPING;
+import static java.util.Collections.singletonList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.anyVararg;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.refEq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SchedulerJobServiceImplTest {
+    private static final String AUDIT_MESSAGE = "Scheduled action, requested for notebook %s";
+    private final String USER = "test";
+    private final String EXPLORATORY_NAME = "explName";
+    private final String COMPUTATIONAL_NAME = "compName";
+    private final String PROJECT = "project";
+    private SchedulerJobDTO schedulerJobDTO;
+    private UserInstanceDTO userInstance;
+
+    @Mock
+    private SchedulerJobDAO schedulerJobDAO;
+    @Mock
+    private ExploratoryDAO exploratoryDAO;
+    @Mock
+    private ComputationalDAO computationalDAO;
+    @Mock
+    private SecurityService securityService;
+    @Mock
+    private ExploratoryService exploratoryService;
+    @Mock
+    private ComputationalService computationalService;
+
+    @InjectMocks
+    private SchedulerJobServiceImpl schedulerJobService;
+
+
+    @Before
+    public void setUp() {
+        schedulerJobDTO = getSchedulerJobDTO(LocalDate.now(), LocalDate.now().plusDays(1),
+                Arrays.asList(DayOfWeek.values()), Arrays.asList(DayOfWeek.values()), false,
+                LocalDateTime.of(LocalDate.now(), LocalTime.now().truncatedTo(ChronoUnit.MINUTES)),
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        userInstance = getUserInstanceDTO();
+    }
+
+    @Test
+    public void fetchSchedulerJobForUserAndExploratory() {
+        when(schedulerJobDAO.fetchSingleSchedulerJobByUserAndExploratory(anyString(), anyString(), anyString()))
+                .thenReturn(Optional.of(schedulerJobDTO));
+
+        SchedulerJobDTO actualSchedulerJobDto =
+                schedulerJobService.fetchSchedulerJobForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME);
+        assertNotNull(actualSchedulerJobDto);
+        assertEquals(schedulerJobDTO, actualSchedulerJobDto);
+
+        verify(schedulerJobDAO).fetchSingleSchedulerJobByUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(exploratoryDAO, schedulerJobDAO);
+    }
+
+    @Test
+    public void fetchSchedulerJobForUserAndExploratoryWhenNotebookNotExist() {
+        when(schedulerJobDAO.fetchSingleSchedulerJobByUserAndExploratory(anyString(), anyString(), anyString())).thenReturn(Optional.empty());
+        try {
+            schedulerJobService.fetchSchedulerJobForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME);
+        } catch (ResourceNotFoundException e) {
+            assertEquals("Scheduler job data not found for user test with exploratory explName", e.getMessage());
+        }
+        verify(schedulerJobDAO).fetchSingleSchedulerJobByUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(schedulerJobDAO);
+    }
+
+    @Test
+    public void fetchEmptySchedulerJobForUserAndExploratory() {
+        when(schedulerJobDAO.fetchSingleSchedulerJobByUserAndExploratory(anyString(), anyString(), anyString()))
+                .thenReturn(Optional.empty());
+        try {
+            schedulerJobService.fetchSchedulerJobForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME);
+        } catch (ResourceNotFoundException e) {
+            assertEquals("Scheduler job data not found for user test with exploratory explName", e.getMessage());
+        }
+        verify(schedulerJobDAO).fetchSingleSchedulerJobByUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(schedulerJobDAO);
+    }
+
+    @Test
+    public void fetchSchedulerJobForComputationalResource() {
+        when(schedulerJobDAO.fetchSingleSchedulerJobForCluster(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(Optional.of(schedulerJobDTO));
+
+        SchedulerJobDTO actualSchedulerJobDto = schedulerJobService
+                .fetchSchedulerJobForComputationalResource(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
+        assertNotNull(actualSchedulerJobDto);
+        assertEquals(schedulerJobDTO, actualSchedulerJobDto);
+
+        verify(schedulerJobDAO).fetchSingleSchedulerJobForCluster(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
+        verifyNoMoreInteractions(computationalDAO, schedulerJobDAO);
+    }
+
+    @Test
+    public void fetchEmptySchedulerJobForComputationalResource() {
+        when(schedulerJobDAO.fetchSingleSchedulerJobForCluster(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(Optional.empty());
+        try {
+            schedulerJobService.fetchSchedulerJobForComputationalResource(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
+        } catch (ResourceNotFoundException e) {
+            assertEquals("Scheduler job data not found for user test with exploratory explName with " +
+                    "computational resource compName", e.getMessage());
+        }
+        verify(schedulerJobDAO).fetchSingleSchedulerJobForCluster(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
+        verifyNoMoreInteractions(computationalDAO, schedulerJobDAO);
+    }
+
+    @Test
+    public void updateSchedulerDataForUserAndExploratory() {
+        userInstance.withStatus("running");
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        when(exploratoryDAO.updateSchedulerDataForUserAndExploratory(anyString(), anyString(), anyString(),
+                any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
+
+        schedulerJobService.updateExploratorySchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(exploratoryDAO).updateSchedulerDataForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
+        verify(computationalDAO).updateSchedulerSyncFlag(USER, PROJECT, EXPLORATORY_NAME, false);
+        verifyNoMoreInteractions(exploratoryDAO);
+        verifyZeroInteractions(computationalDAO);
+    }
+
+    @Test
+    public void updateSchedulerDataForUserAndExploratoryWhenMethodFetchExploratoryFieldsThrowsException() {
+        doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
+                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
+        try {
+            schedulerJobService.updateExploratorySchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
+        } catch (ResourceNotFoundException e) {
+            assertEquals("Exploratory for user with name not found", e.getMessage());
+        }
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(exploratoryDAO);
+        verifyZeroInteractions(computationalDAO);
+    }
+
+    @Test
+    public void updateSchedulerDataForUserAndExploratoryWithInapproprietaryStatus() {
+        userInstance.withStatus("terminated");
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        try {
+            schedulerJobService.updateExploratorySchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
+        } catch (ResourceInappropriateStateException e) {
+            assertEquals("Can not create/update scheduler for user instance with status: terminated",
+                    e.getMessage());
+        }
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verifyNoMoreInteractions(exploratoryDAO);
+        verifyZeroInteractions(computationalDAO);
+    }
+
+    @Test
+    public void updateSchedulerDataForUserAndExploratoryWithEnrichingSchedulerJob() {
+        schedulerJobDTO.setBeginDate(null);
+        schedulerJobDTO.setTimeZoneOffset(null);
+        userInstance.withStatus("running");
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        when(exploratoryDAO.updateSchedulerDataForUserAndExploratory(anyString(), anyString(), anyString(),
+                any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
+
+        assertNull(schedulerJobDTO.getBeginDate());
+        assertNull(schedulerJobDTO.getTimeZoneOffset());
+
+        schedulerJobService.updateExploratorySchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
+
+        assertEquals(LocalDate.now(), schedulerJobDTO.getBeginDate());
+        assertEquals(OffsetDateTime.now(ZoneId.systemDefault()).getOffset(), schedulerJobDTO.getTimeZoneOffset());
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(exploratoryDAO).updateSchedulerDataForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
+        verify(computationalDAO).updateSchedulerSyncFlag(USER, PROJECT, EXPLORATORY_NAME, false);
+        verifyNoMoreInteractions(exploratoryDAO);
+        verifyZeroInteractions(computationalDAO);
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void updateSchedulerDataForUserAndExploratoryWithSyncStartRequiredParam() {
+        userInstance.withStatus("running");
+        schedulerJobDTO.setSyncStartRequired(true);
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        when(exploratoryDAO.updateSchedulerDataForUserAndExploratory(anyString(), anyString(), anyString(),
+                any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
+        when(computationalDAO.getComputationalResourcesWhereStatusIn(anyString(), anyString(),
+                any(List.class), anyString(), anyVararg())).thenReturn(singletonList(COMPUTATIONAL_NAME));
+        when(computationalDAO.updateSchedulerDataForComputationalResource(anyString(), anyString(), anyString(),
+                anyString(), any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
+
+        schedulerJobService.updateExploratorySchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(exploratoryDAO).updateSchedulerDataForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
+        verify(computationalDAO).getComputationalResourcesWhereStatusIn(USER, PROJECT,
+                singletonList(DataEngineType.SPARK_STANDALONE), EXPLORATORY_NAME, STARTING, RUNNING, STOPPING, STOPPED);
+        schedulerJobDTO.setEndTime(null);
+        schedulerJobDTO.setStopDaysRepeat(Collections.emptyList());
+        verify(computationalDAO).updateSchedulerDataForComputationalResource(USER, PROJECT,
+                EXPLORATORY_NAME, COMPUTATIONAL_NAME, schedulerJobDTO);
+        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void updateSchedulerDataForUserAndExploratoryWithSyncStartRequiredParamButAbsenceClusters() {
+        userInstance.withStatus("running");
+        schedulerJobDTO.setSyncStartRequired(true);
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        when(exploratoryDAO.updateSchedulerDataForUserAndExploratory(anyString(), anyString(), anyString(),
+                any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
+        when(computationalDAO.getComputationalResourcesWhereStatusIn(anyString(), anyString(),
+                any(List.class), anyString(), anyVararg())).thenReturn(Collections.emptyList());
+
+        schedulerJobService.updateExploratorySchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(exploratoryDAO).updateSchedulerDataForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
+        verify(computationalDAO).getComputationalResourcesWhereStatusIn(USER, PROJECT,
+                singletonList(DataEngineType.SPARK_STANDALONE), EXPLORATORY_NAME, STARTING, RUNNING, STOPPING, STOPPED);
+        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
+    }
+
+    @Test
+    public void updateSchedulerDataForComputationalResource() {
+        userInstance.withStatus("running");
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(userInstance.getResources().get(0));
+        when(computationalDAO.updateSchedulerDataForComputationalResource(anyString(), anyString(), anyString(),
+                anyString(), any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
+
+        schedulerJobService.updateComputationalSchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME,
+                COMPUTATIONAL_NAME, schedulerJobDTO);
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
+        verify(computationalDAO).updateSchedulerDataForComputationalResource(USER, PROJECT,
+                EXPLORATORY_NAME, COMPUTATIONAL_NAME, schedulerJobDTO);
+        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
+    }
+
+    @Test
+    public void updateSchedulerDataForComputationalResourceWhenSchedulerIsNull() {
+        userInstance.withStatus("running");
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(userInstance.getResources().get(0));
+        when(computationalDAO.updateSchedulerDataForComputationalResource(anyString(), anyString(), anyString(),
+                anyString(), any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
+
+        final SchedulerJobDTO schedulerJobDTO = getSchedulerJobDTO(LocalDate.now(), LocalDate.now().plusDays(1),
+                Arrays.asList(DayOfWeek.values()), Arrays.asList(DayOfWeek.values()), false,
+                LocalDateTime.of(LocalDate.now(), LocalTime.now().truncatedTo(ChronoUnit.MINUTES)),
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        schedulerJobDTO.setStartDaysRepeat(null);
+        schedulerJobDTO.setStopDaysRepeat(null);
+        schedulerJobService.updateComputationalSchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME,
+                COMPUTATIONAL_NAME, schedulerJobDTO);
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
+        verify(computationalDAO).updateSchedulerDataForComputationalResource(eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME),
+                eq(COMPUTATIONAL_NAME), refEq(schedulerJobDTO));
+        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
+    }
+
+    @Test
+    public void updateSchedulerDataForComputationalResourceWhenMethodFetchComputationalFieldsThrowsException() {
+        userInstance.withStatus("running");
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        doThrow(new ResourceNotFoundException("Computational resource for user with name not found"))
+                .when(computationalDAO).fetchComputationalFields(anyString(), anyString(), anyString(), anyString());
+        try {
+            schedulerJobService.updateComputationalSchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME, schedulerJobDTO);
+        } catch (ResourceNotFoundException e) {
+            assertEquals("Computational resource for user with name not found", e.getMessage());
+        }
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
+        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
+    }
+
+    @Test
+    public void updateSchedulerDataForComputationalResourceWithInapproprietaryClusterStatus() {
+        userInstance.setStatus("running");
+        userInstance.getResources().get(0).setStatus("terminated");
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(userInstance.getResources().get(0));
+        try {
+            schedulerJobService.updateComputationalSchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME, schedulerJobDTO);
+        } catch (ResourceInappropriateStateException e) {
+            assertEquals("Can not create/update scheduler for user instance with status: terminated",
+                    e.getMessage());
+        }
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
+        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
+    }
+
+    @Test
+    public void updateSchedulerDataForComputationalResourceWithEnrichingSchedulerJob() {
+        schedulerJobDTO.setBeginDate(null);
+        schedulerJobDTO.setTimeZoneOffset(null);
+        userInstance.withStatus("running");
+        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
+        when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString()))
+                .thenReturn(userInstance.getResources().get(0));
+        when(computationalDAO.updateSchedulerDataForComputationalResource(anyString(), anyString(), anyString(),
+                anyString(), any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
+
+        assertNull(schedulerJobDTO.getBeginDate());
+        assertNull(schedulerJobDTO.getTimeZoneOffset());
+
+        schedulerJobService.updateComputationalSchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME,
+                COMPUTATIONAL_NAME, schedulerJobDTO);
+
+        assertEquals(LocalDate.now(), schedulerJobDTO.getBeginDate());
+        assertEquals(OffsetDateTime.now(ZoneId.systemDefault()).getOffset(), schedulerJobDTO.getTimeZoneOffset());
+
+        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
+        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
+        verify(computationalDAO).updateSchedulerDataForComputationalResource(USER, PROJECT,
+                EXPLORATORY_NAME, COMPUTATIONAL_NAME, schedulerJobDTO);
+        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
+    }
+
+    @Test
+    public void testStartComputationalByScheduler() {
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).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());
+
+        schedulerJobService.startComputationalByScheduler();
+
+        verify(securityService).getServiceAccountInfo(USER);
+        verify(schedulerJobDAO)
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, STOPPED);
+        verify(computationalService).startSparkCluster(refEq(getUserInfo()), eq(EXPLORATORY_NAME),
+                eq(COMPUTATIONAL_NAME), eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
+
+    @Test
+    public void testStartComputationalBySchedulerWhenSchedulerIsNotConfigured() {
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(Collections.emptyList());
+
+        schedulerJobService.startComputationalByScheduler();
+
+        verify(schedulerJobDAO).getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE,
+                STOPPED);
+        verifyNoMoreInteractions(schedulerJobDAO);
+        verifyZeroInteractions(securityService, computationalService);
+    }
+
+    @Test
+    public void testStartComputationalBySchedulerWhenSchedulerFinishDateBeforeNow() {
+        final LocalDate beginDate = LocalDate.now().plusDays(1);
+        final LocalDate endDate = LocalDate.now();
+        final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(beginDate, endDate, startDays, stopDays,
+                terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.startComputationalByScheduler();
+
+        verify(schedulerJobDAO)
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, STOPPED);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
+
+    @Test
+    public void testStartComputationalBySchedulerWhenSchedulerStartDateAfterNow() {
+        final LocalDate beginDate = LocalDate.now().plusDays(1);
+        final LocalDate finishDate = LocalDate.now();
+        final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(
+                beginDate, finishDate, startDays, stopDays, terminateDateTime, false, USER,
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.startComputationalByScheduler();
+
+        verify(schedulerJobDAO)
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, STOPPED);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
+
+    @Test
+    public void testStartComputationalBySchedulerWhenStartDayIsNotCurrentDay() {
+        final List<DayOfWeek> stopDays = Arrays.stream(DayOfWeek.values()).collect(Collectors.toList());
+        final List<DayOfWeek> startDays = Arrays.stream(DayOfWeek.values()).collect(Collectors.toList());
+        startDays.remove(LocalDate.now().getDayOfWeek());
+        final LocalDate beginDate = LocalDate.now();
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(
+                beginDate, LocalDate.now().minusDays(1), startDays, stopDays,
+                LocalDateTime.of(LocalDate.now(),
+                        LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+        );
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.startComputationalByScheduler();
+
+        verify(schedulerJobDAO)
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, STOPPED);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
+
+
+    @Test
+    public void testStopComputationalByScheduler() {
+        UserInfo userInfo = getUserInfo();
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).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(userInfo);
+
+        schedulerJobService.stopComputationalByScheduler();
+
+        verify(securityService).getServiceAccountInfo(USER);
+        verify(schedulerJobDAO)
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING);
+        verify(computationalService).stopSparkCluster(refEq(userInfo), eq(userInfo.getName()), eq(PROJECT),
+                eq(EXPLORATORY_NAME), eq(COMPUTATIONAL_NAME), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
+
+    @Test
+    public void testStopComputationalBySchedulerWhenSchedulerIsNotConfigured() {
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(Collections.emptyList());
+
+        schedulerJobService.stopComputationalByScheduler();
+
+        verify(schedulerJobDAO)
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING);
+        verifyNoMoreInteractions(schedulerJobDAO);
+        verifyZeroInteractions(securityService, computationalService);
+    }
+
+    @Test
+    public void testStopComputationalBySchedulerWhenSchedulerFinishDateBeforeNow() {
+        final LocalDate beginDate = LocalDate.now().plusDays(1);
+        final LocalDate endDate = LocalDate.now();
+        final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(beginDate, endDate, startDays, stopDays,
+                terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.stopComputationalByScheduler();
+
+        verify(schedulerJobDAO)
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
+
+    @Test
+    public void testStopComputationalBySchedulerWhenSchedulerStartDateAfterNow() {
+        final LocalDate beginDate = LocalDate.now().plusDays(1);
+        final LocalDate finishDate = LocalDate.now();
+        final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(
+                beginDate, finishDate, startDays, stopDays, terminateDateTime, false, USER,
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.stopComputationalByScheduler();
+
+        verify(schedulerJobDAO)
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
+
+    @Test
+    public void testStopComputationalBySchedulerWhenStopDayIsNotCurrentDay() {
+        final List<DayOfWeek> stopDays = Arrays.stream(DayOfWeek.values()).collect(Collectors.toList());
+        stopDays.remove(LocalDate.now().getDayOfWeek());
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(
+                LocalDate.now(), LocalDate.now().minusDays(1), Arrays.asList(DayOfWeek.values()), stopDays,
+                LocalDateTime.of(LocalDate.now(),
+                        LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+        );
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.stopComputationalByScheduler();
+
+        verify(schedulerJobDAO)
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
+
+
+    @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(userInfo);
+
+        schedulerJobService.stopExploratoryByScheduler();
+
+        verify(securityService).getServiceAccountInfo(USER);
+        verify(schedulerJobDAO).getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(eq(RUNNING),
+                any(Date.class));
+        verify(exploratoryService).stop(refEq(userInfo), eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService);
+    }
+
+    @Test
+    public void testStopExploratoryBySchedulerWhenSchedulerIsNotConfigured() {
+        when(schedulerJobDAO.getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(any(UserInstanceStatus.class), any(Date.class)))
+                .thenReturn(Collections.emptyList());
+
+        schedulerJobService.stopExploratoryByScheduler();
+
+        verify(schedulerJobDAO).getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(eq(RUNNING),
+                any(Date.class));
+        verifyNoMoreInteractions(schedulerJobDAO);
+        verifyZeroInteractions(securityService, exploratoryService);
+    }
+
+    @Test
+    public void testStopExploratoryBySchedulerWhenSchedulerFinishDateBeforeNow() {
+        final LocalDate finishDate = LocalDate.now().minusDays(1);
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(LocalDate.now(), finishDate,
+                Arrays.asList(DayOfWeek.values()), stopDays, LocalDateTime.of(LocalDate.now(),
+                        LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+        );
+        when(schedulerJobDAO.getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(any(UserInstanceStatus.class), any(Date.class))).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.stopExploratoryByScheduler();
+
+        verify(schedulerJobDAO).getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(eq(RUNNING),
+                any(Date.class));
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService);
+    }
+
+    @Test
+    public void testStopExploratoryBySchedulerWhenSchedulerStartDateAfterNow() {
+        final LocalDate now = LocalDate.now();
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
+        final LocalDate beginDate = now.plusDays(1);
+        final LocalDateTime terminateDateTime = LocalDateTime.of(now, LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(beginDate, now, startDays, stopDays,
+                terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+        );
+        when(schedulerJobDAO.getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(any(UserInstanceStatus.class), any(Date.class)))
+                .thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.stopExploratoryByScheduler();
+
+        verify(schedulerJobDAO).getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(eq(RUNNING),
+                any(Date.class));
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService);
+    }
+
+    @Test
+    public void testStopExploratoryBySchedulerWhenStopDayIsNotCurrentDay() {
+        final List<DayOfWeek> stopDays = Arrays.stream((DayOfWeek.values())).collect(Collectors.toList());
+        stopDays.remove(LocalDate.now().getDayOfWeek());
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(
+                LocalDate.now(), LocalDate.now().minusDays(1), Arrays.asList(DayOfWeek.values()), stopDays,
+                LocalDateTime.of(LocalDate.now(),
+                        LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+        );
+        when(schedulerJobDAO.getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(any(UserInstanceStatus.class), any(Date.class))).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.stopExploratoryByScheduler();
+
+        verify(schedulerJobDAO).getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(eq(RUNNING),
+                any(Date.class));
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService);
+    }
+
+
+    @Test
+    public void testStartExploratoryByScheduler() {
+        final LocalDate finishDate = LocalDate.now().plusDays(1);
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class)))
+                .thenReturn(singletonList(getSchedulerJobData(LocalDate.now(), finishDate,
+                        Arrays.asList(DayOfWeek.values()), stopDays, LocalDateTime.of(LocalDate.now(),
+                                LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
+                        LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+                )));
+        when(securityService.getServiceAccountInfo(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.startExploratoryByScheduler();
+
+        verify(securityService).getServiceAccountInfo(USER);
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
+        verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService);
+        verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
+        verifyNoMoreInteractions(schedulerJobDAO, exploratoryService);
+        verifyZeroInteractions(computationalService, computationalDAO);
+    }
+
+    @Test
+    public void testStartExploratoryBySchedulerWithSyncComputationalStart() {
+        final LocalDate finishDate = LocalDate.now().plusDays(1);
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class)))
+                .thenReturn(singletonList(getSchedulerJobData(LocalDate.now(), finishDate,
+                        Arrays.asList(DayOfWeek.values()), stopDays, LocalDateTime.of(LocalDate.now(),
+                                LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), true, USER,
+                        LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+                )));
+        when(securityService.getServiceAccountInfo(anyString())).thenReturn(getUserInfo());
+        when(computationalDAO.findComputationalResourcesWithStatus(anyString(), anyString(),
+                anyString(), any(UserInstanceStatus.class))).thenReturn(singletonList(getComputationalResource(
+                DataEngineType.SPARK_STANDALONE, true)));
+
+        schedulerJobService.startExploratoryByScheduler();
+
+        verify(securityService, times(2)).getServiceAccountInfo(USER);
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
+        verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
+        verify(computationalDAO).findComputationalResourcesWithStatus(USER, PROJECT, EXPLORATORY_NAME, STOPPED);
+        verify(computationalService).startSparkCluster(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(COMPUTATIONAL_NAME),
+                eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService, computationalService,
+                computationalDAO);
+    }
+
+    @Test
+    public void testStartExploratoryBySchedulerWithSyncComputationalStartDataEngine() {
+        final LocalDate finishDate = LocalDate.now().plusDays(1);
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class)))
+                .thenReturn(singletonList(getSchedulerJobData(LocalDate.now(), finishDate,
+                        Arrays.asList(DayOfWeek.values()), stopDays, LocalDateTime.of(LocalDate.now(),
+                                LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), true, USER,
+                        LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+                )));
+        when(securityService.getServiceAccountInfo(anyString())).thenReturn(getUserInfo());
+        when(computationalDAO.findComputationalResourcesWithStatus(anyString(), anyString(),
+                anyString(), any(UserInstanceStatus.class))).thenReturn(singletonList(getComputationalResource(
+                DataEngineType.CLOUD_SERVICE, true)));
+
+        schedulerJobService.startExploratoryByScheduler();
+
+        verify(securityService).getServiceAccountInfo(USER);
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
+        verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
+        verify(computationalDAO).findComputationalResourcesWithStatus(USER, PROJECT, EXPLORATORY_NAME, STOPPED);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService, computationalDAO);
+        verifyZeroInteractions(computationalService);
+    }
+
+    @Test
+    public void testStartExploratoryBySchedulerWithSyncComputationalStartOnExploratoryButNotOnComputational() {
+        final LocalDate finishDate = LocalDate.now().plusDays(1);
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class)))
+                .thenReturn(singletonList(getSchedulerJobData(LocalDate.now(), finishDate,
+                        Arrays.asList(DayOfWeek.values()), stopDays, LocalDateTime.of(LocalDate.now(),
+                                LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), true, USER,
+                        LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+                )));
+        when(securityService.getServiceAccountInfo(anyString())).thenReturn(getUserInfo());
+        when(computationalDAO.findComputationalResourcesWithStatus(anyString(), anyString(),
+                anyString(), any(UserInstanceStatus.class))).thenReturn(singletonList(getComputationalResource(
+                DataEngineType.SPARK_STANDALONE, false)));
+
+        schedulerJobService.startExploratoryByScheduler();
+
+        verify(securityService).getServiceAccountInfo(USER);
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
+        verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
+        verify(computationalDAO).findComputationalResourcesWithStatus(USER, PROJECT, EXPLORATORY_NAME, STOPPED);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService, computationalDAO);
+        verifyZeroInteractions(computationalService);
+    }
+
+    @Test
+    public void testStartExploratoryBySchedulerWhenSchedulerIsNotConfigured() {
+        when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class))).thenReturn(Collections.emptyList());
+
+        schedulerJobService.startExploratoryByScheduler();
+
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
+        verifyNoMoreInteractions(schedulerJobDAO);
+        verifyZeroInteractions(securityService, exploratoryService, computationalService, computationalDAO);
+    }
+
+    @Test
+    public void testStartExploratoryBySchedulerWhenSchedulerFinishDateBeforeNow() {
+        final LocalDate finishDate = LocalDate.now().minusDays(1);
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(LocalDate.now(), finishDate,
+                Arrays.asList(DayOfWeek.values()), stopDays, LocalDateTime.of(LocalDate.now(),
+                        LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+        );
+        when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class))).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.startExploratoryByScheduler();
+
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
+        verifyZeroInteractions(securityService, exploratoryService, computationalService, computationalDAO);
+    }
+
+    @Test
+    public void testStartExploratoryBySchedulerWhenSchedulerStartDateAfterNow() {
+        final LocalDate finishDate = LocalDate.now();
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        final LocalDate beginDate = LocalDate.now().plusDays(1);
+        final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
+        final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(beginDate, finishDate, startDays, stopDays,
+                terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class))).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.startExploratoryByScheduler();
+
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
+        verifyZeroInteractions(securityService, exploratoryService, computationalService, computationalDAO);
+    }
+
+    @Test
+    public void testStartExploratoryBySchedulerWhenStartDayIsNotCurrentDay() {
+        final List<DayOfWeek> stopDays = Arrays.stream((DayOfWeek.values())).collect(Collectors.toList());
+        final List<DayOfWeek> startDays = Arrays.stream(DayOfWeek.values()).collect(Collectors.toList());
+        startDays.remove(LocalDate.now().getDayOfWeek());
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(
+                LocalDate.now(), LocalDate.now().minusDays(1), startDays, stopDays, LocalDateTime.of(LocalDate.now(),
+                        LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class))).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.startExploratoryByScheduler();
+
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
+        verifyZeroInteractions(securityService, exploratoryService, computationalService, computationalDAO);
+    }
+
+
+    @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));
+        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(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
+
+    @Test
+    public void testTerminateComputationalBySchedulerWhenSchedulerIsNotConfigured() {
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(Collections.emptyList());
+
+        schedulerJobService.terminateComputationalByScheduler();
+
+        verify(schedulerJobDAO).getComputationalSchedulerDataWithOneOfStatus(RUNNING, STOPPED, RUNNING);
+        verifyNoMoreInteractions(schedulerJobDAO);
+        verifyZeroInteractions(securityService, computationalService);
+    }
+
+    @Test
+    public void testTerminateComputationalBySchedulerWhenSchedulerFinishDateBeforeNow() {
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(
+                LocalDate.now(), LocalDate.now().minusDays(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(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.terminateComputationalByScheduler();
+
+        verify(schedulerJobDAO).getComputationalSchedulerDataWithOneOfStatus(RUNNING, STOPPED, RUNNING);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
+
+    @Test
+    public void testTerminateComputationalBySchedulerWhenSchedulerStartDateAfterNow() {
+        final LocalDate beginDate = LocalDate.now().plusDays(1);
+        final LocalDate finishDate = LocalDate.now();
+        final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(beginDate, finishDate, startDays, stopDays,
+                terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.terminateComputationalByScheduler();
+
+        verify(schedulerJobDAO).getComputationalSchedulerDataWithOneOfStatus(RUNNING, STOPPED, RUNNING);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
+
+    @Test
+    public void testTerminateComputationalBySchedulerWhenTerminateDateNotCurrent() {
+        final List<DayOfWeek> stopDays = Arrays.stream(DayOfWeek.values()).collect(Collectors.toList());
+        stopDays.remove(LocalDate.now().getDayOfWeek());
+        final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES)).plusDays(1);
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(
+                LocalDate.now(), LocalDate.now().minusDays(1), Arrays.asList(DayOfWeek.values()), stopDays,
+                terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+        );
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.terminateComputationalByScheduler();
+
+        verify(schedulerJobDAO)
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, STOPPED, RUNNING);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
+
+    @Test
+    public void testTerminateExploratoryByScheduler() {
+        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.getExploratorySchedulerDataWithOneOfStatus(anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.terminateExploratoryByScheduler();
+
+        verify(securityService).getUserInfoOffline(USER);
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED);
+        verify(exploratoryService).terminate(refEq(getUserInfo()), eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService, exploratoryService);
+    }
+
+    @Test
+    public void testTerminateExploratoryBySchedulerWhenSchedulerIsNotConfigured() {
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(Collections.emptyList());
+
+        schedulerJobService.terminateExploratoryByScheduler();
+
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED);
+        verifyNoMoreInteractions(schedulerJobDAO);
+        verifyZeroInteractions(securityService, exploratoryService, computationalService);
+    }
+
+    @Test
+    public void testTerminateExploratoryBySchedulerWhenSchedulerFinishDateBeforeNow() {
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(
+                LocalDate.now(), LocalDate.now().minusDays(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(schedulerJobDAO.getExploratorySchedulerDataWithOneOfStatus(anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.terminateExploratoryByScheduler();
+
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService, computationalService);
+    }
+
+    @Test
+    public void testTerminateExploratoryBySchedulerWhenSchedulerStartDateAfterNow() {
+        final LocalDate beginDate = LocalDate.now().plusDays(1);
+        final LocalDate finishDate = LocalDate.now();
+        final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(
+                beginDate, finishDate, startDays, stopDays, terminateDateTime, false, USER,
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        when(schedulerJobDAO.getExploratorySchedulerDataWithOneOfStatus(anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.terminateExploratoryByScheduler();
+
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService, computationalService);
+    }
+
+    @Test
+    public void testTerminateExploratoryBySchedulerWhenTerminateDateNotCurrent() {
+        final List<DayOfWeek> stopDays = Arrays.stream(DayOfWeek.values()).collect(Collectors.toList());
+        stopDays.remove(LocalDate.now().getDayOfWeek());
+        final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES)).plusDays(1);
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(
+                LocalDate.now(), LocalDate.now().minusDays(1), Arrays.asList(DayOfWeek.values()), stopDays,
+                terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+        );
+        when(schedulerJobDAO.getExploratorySchedulerDataWithOneOfStatus(anyVararg())).thenReturn(singletonList(schedulerJobData));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+
+        schedulerJobService.terminateExploratoryByScheduler();
+
+        verify(schedulerJobDAO).getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED);
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService, exploratoryService);
+    }
+
+    @Test
+    public void testGetActiveSchedulers() {
+        final int minutesOffset = 123;
+        final LocalDate now = LocalDate.now();
+        final DayOfWeek[] weekDays = DayOfWeek.values();
+        final LocalTime currentTime = LocalTime.now();
+        final LocalTime offsetTime = LocalTime.now().plusMinutes(1);
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(now,
+                now.plusDays(1), Arrays.asList(weekDays), Arrays.asList(weekDays),
+                LocalDateTime.of(now, currentTime.plusMinutes(minutesOffset).truncatedTo(ChronoUnit.MINUTES)), false,
+                USER, offsetTime.truncatedTo(ChronoUnit.MINUTES));
+
+        final SchedulerJobData secondScheduler = getSchedulerJobData(now,
+                now.plusDays(1), Arrays.asList(weekDays), Arrays.asList(weekDays),
+                LocalDateTime.of(now, currentTime.plusMinutes(minutesOffset).truncatedTo(ChronoUnit.MINUTES)),
+                false, "user123", offsetTime.truncatedTo(ChronoUnit.MINUTES));
+
+        when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class))).thenReturn(Arrays.asList(schedulerJobData, secondScheduler));
+        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
+
+        final List<SchedulerJobData> activeSchedulers = schedulerJobService.getActiveSchedulers(USER, minutesOffset);
+
+        assertEquals(2, activeSchedulers.size());
+    }
+
+    private SchedulerJobData getSchedulerJobData(LocalDate beginDate, LocalDate schedulerFinishDate,
+                                                 List<DayOfWeek> startDays, List<DayOfWeek> stopDays,
+                                                 LocalDateTime terminateDateTime, boolean syncStartRequired,
+                                                 String user, LocalTime endTime) {
+        return new SchedulerJobData(user, EXPLORATORY_NAME, COMPUTATIONAL_NAME, PROJECT, getSchedulerJobDTO(beginDate,
+                schedulerFinishDate, startDays, stopDays, syncStartRequired, terminateDateTime, endTime));
+    }
+
+    private UserInfo getUserInfo() {
+        return new UserInfo(USER, "token");
+    }
+
+    private SchedulerJobDTO getSchedulerJobDTO(LocalDate beginDate, LocalDate finishDate, List<DayOfWeek> startDays,
+                                               List<DayOfWeek> stopDays, boolean syncStartRequired,
+                                               LocalDateTime terminateDateTime, LocalTime endTime) {
+        SchedulerJobDTO schedulerJobDTO = new SchedulerJobDTO();
+        schedulerJobDTO.setTimeZoneOffset(OffsetDateTime.now(ZoneId.systemDefault()).getOffset());
+        schedulerJobDTO.setBeginDate(beginDate);
+        schedulerJobDTO.setFinishDate(finishDate);
+        schedulerJobDTO.setStartTime(LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        schedulerJobDTO.setEndTime(endTime);
+        schedulerJobDTO.setTerminateDateTime(terminateDateTime);
+        schedulerJobDTO.setStartDaysRepeat(startDays);
+        schedulerJobDTO.setStopDaysRepeat(stopDays);
+        schedulerJobDTO.setSyncStartRequired(syncStartRequired);
+        return schedulerJobDTO;
+    }
+
+    private UserInstanceDTO getUserInstanceDTO() {
+        UserComputationalResource computationalResource = new UserComputationalResource();
+        computationalResource.setStatus("running");
+        return new UserInstanceDTO()
+                .withUser(USER)
+                .withExploratoryName(EXPLORATORY_NAME)
+                .withResources(singletonList(computationalResource))
+                .withProject(PROJECT);
+    }
+
+    private AwsComputationalResource getComputationalResource(DataEngineType dataEngineType,
+                                                              boolean syncStartRequired) {
+        final SchedulerJobDTO schedulerJobData = new SchedulerJobDTO();
+        schedulerJobData.setSyncStartRequired(syncStartRequired);
+        return AwsComputationalResource.builder()
+                .computationalName("compName")
+                .imageName(DataEngineType.getDockerImageName(dataEngineType))
+                .schedulerJobData(schedulerJobData)
+                .build();
+    }
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/SystemInfoServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/SystemInfoServiceImplTest.java
new file mode 100644
index 0000000..e3e01a3
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/SystemInfoServiceImplTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.resources.dto.SystemInfoDto;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import oshi.SystemInfo;
+import oshi.hardware.CentralProcessor;
+import oshi.hardware.GlobalMemory;
+import oshi.hardware.HWDiskStore;
+import oshi.hardware.HardwareAbstractionLayer;
+import oshi.software.os.FileSystem;
+import oshi.software.os.OSFileStore;
+import oshi.software.os.OperatingSystem;
+import oshi.software.os.OperatingSystemVersion;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SystemInfoServiceImplTest {
+
+    private static final String OS_VERSION = "OS version";
+    private static final String OS_FAMILY = "OS FAMILY";
+    private static final String BUILD_NUMBER = "BUILD 1.0";
+    private static final String PROCESSOR_MODEL = "Proc model";
+    private static final long AVAILABLE_MEMORY = 100L;
+    private static final long USABLE_SPACE = 100L;
+    private static final long TOTAL_SPACE = 1000L;
+    @Mock
+    private SystemInfo si;
+
+    @InjectMocks
+    private SystemInfoServiceImpl systemInfoService;
+
+    @Test
+    public void getSystemInfo() {
+        final OperatingSystem os = mock(OperatingSystem.class);
+        final HardwareAbstractionLayer hardwareAbstractionLayer = mock(HardwareAbstractionLayer.class);
+        final OperatingSystemVersion operatingSystemVersion = mock(OperatingSystemVersion.class);
+        final CentralProcessor centralProcessor = mock(CentralProcessor.class);
+        final GlobalMemory globalMemory = mock(GlobalMemory.class);
+        final FileSystem fileSystem = mock(FileSystem.class);
+        final OSFileStore osFileStore = new OSFileStore();
+        osFileStore.setUsableSpace(USABLE_SPACE);
+        osFileStore.setTotalSpace(TOTAL_SPACE);
+        when(fileSystem.getFileStores()).thenReturn(new OSFileStore[]{osFileStore});
+
+        when(operatingSystemVersion.getVersion()).thenReturn(OS_VERSION);
+        when(operatingSystemVersion.getBuildNumber()).thenReturn(BUILD_NUMBER);
+        when(hardwareAbstractionLayer.getDiskStores()).thenReturn(new HWDiskStore[]{});
+        when(os.getFamily()).thenReturn(OS_FAMILY);
+        when(os.getVersion()).thenReturn(operatingSystemVersion);
+        when(si.getOperatingSystem()).thenReturn(os);
+        when(os.getFileSystem()).thenReturn(fileSystem);
+        when(globalMemory.getAvailable()).thenReturn(AVAILABLE_MEMORY);
+        when(hardwareAbstractionLayer.getMemory()).thenReturn(globalMemory);
+        when(centralProcessor.getModel()).thenReturn(PROCESSOR_MODEL);
+        when(hardwareAbstractionLayer.getProcessor()).thenReturn(centralProcessor);
+        when(si.getHardware()).thenReturn(hardwareAbstractionLayer);
+
+        SystemInfoDto systemInfo = systemInfoService.getSystemInfo();
+
+        assertEquals(BUILD_NUMBER, systemInfo.getOsInfo().getBuildNumber());
+        assertEquals(OS_VERSION, systemInfo.getOsInfo().getVersion());
+        assertEquals(OS_FAMILY, systemInfo.getOsInfo().getFamily());
+        assertEquals(PROCESSOR_MODEL, systemInfo.getProcessorInfo().getModel());
+        assertEquals(AVAILABLE_MEMORY, systemInfo.getMemoryInfo().getAvailableMemory());
+        assertEquals(1, systemInfo.getDisksInfo().size());
+
+        verify(si).getOperatingSystem();
+        verify(si).getHardware();
+        verifyNoMoreInteractions(si, fileSystem);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/UserGroupServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/UserGroupServiceImplTest.java
new file mode 100644
index 0000000..1ad7bd0
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/UserGroupServiceImplTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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.datalab.backendapi.service.impl;
+
+import com.epam.datalab.backendapi.dao.ProjectDAO;
+import com.epam.datalab.backendapi.dao.UserGroupDAO;
+import com.epam.datalab.backendapi.dao.UserRoleDAO;
+import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.resources.TestBase;
+import com.epam.datalab.backendapi.resources.dto.UserGroupDto;
+import com.epam.datalab.dto.UserInstanceStatus;
+import com.epam.datalab.exceptions.DatalabException;
+import com.epam.datalab.exceptions.ResourceNotFoundException;
+import io.dropwizard.auth.AuthenticationException;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.anySet;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class UserGroupServiceImplTest extends TestBase {
+
+    private static final String ROLE_ID = "Role id";
+    private static final String USER = "test";
+    private static final String GROUP = "admin";
+    @Mock
+    private UserRoleDAO userRoleDao;
+    @Mock
+    private UserGroupDAO userGroupDao;
+    @Mock
+    private ProjectDAO projectDAO;
+    @InjectMocks
+    private UserGroupServiceImpl userGroupService;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Before
+    public void setup() throws AuthenticationException {
+        authSetup();
+    }
+
+    @Test
+    public void createGroup() {
+        when(userRoleDao.addGroupToRole(anySet(), anySet())).thenReturn(true);
+
+        userGroupService.createGroup(getUserInfo(), GROUP, Collections.singleton(ROLE_ID), Collections.singleton(USER));
+
+        verify(userRoleDao).addGroupToRole(Collections.singleton(GROUP), Collections.singleton(ROLE_ID));
+        verify(userGroupDao).addUsers(GROUP, Collections.singleton(USER));
+    }
+
+    @Test
+    public void createGroupWithNoUsers() {
+        when(userRoleDao.addGroupToRole(anySet(), anySet())).thenReturn(true);
+
+        userGroupService.createGroup(getUserInfo(), GROUP, Collections.singleton(ROLE_ID), Collections.emptySet());
+
+        verify(userRoleDao).addGroupToRole(Collections.singleton(GROUP), Collections.singleton(ROLE_ID));
+        verify(userGroupDao).addUsers(anyString(), anySet());
+    }
+
+    @Test
+    public void createGroupWhenRoleNotFound() {
+        when(userRoleDao.addGroupToRole(anySet(), anySet())).thenReturn(false);
+
+        expectedException.expect(ResourceNotFoundException.class);
+        userGroupService.createGroup(getUserInfo(), GROUP, Collections.singleton(ROLE_ID), Collections.singleton(USER));
+    }
+
+    @Test
+    public void removeGroup() {
+
+        when(userRoleDao.removeGroup(anyString())).thenReturn(true);
+        final ProjectDTO projectDTO = new ProjectDTO(
+                "name", Collections.emptySet(), "", "", null, Collections.emptyList(), true);
+        when(projectDAO.getProjectsWithEndpointStatusNotIn(UserInstanceStatus.TERMINATED,
+                UserInstanceStatus.TERMINATING)).thenReturn(Collections.singletonList(projectDTO));
+        doNothing().when(userGroupDao).removeGroup(anyString());
+
+        userGroupService.removeGroup(getUserInfo(), GROUP);
+
+        verify(userRoleDao).removeGroup(GROUP);
+        verify(userGroupDao).removeGroup(GROUP);
+        verifyNoMoreInteractions(userGroupDao, userRoleDao);
+    }
+
+    @Test
+    public void removeGroupWhenItIsUsedInProject() {
+
+        when(userRoleDao.removeGroup(anyString())).thenReturn(true);
+        when(projectDAO.getProjectsWithEndpointStatusNotIn(UserInstanceStatus.TERMINATED,
+                UserInstanceStatus.TERMINATING)).thenReturn(Collections.singletonList(new ProjectDTO(
+                "name", Collections.singleton(GROUP), "", "", null, Collections.emptyList(), true)));
+        doNothing().when(userGroupDao).removeGroup(anyString());
+
+        try {
+            userGroupService.removeGroup(getUserInfo(), GROUP);
+        } catch (Exception e) {
+            assertEquals("Group can not be removed because it is used in some project", e.getMessage());
+        }
+
+        verify(userRoleDao, never()).removeGroup(GROUP);
+        verify(userGroupDao, never()).removeGroup(GROUP);
+        verifyNoMoreInteractions(userGroupDao, userRoleDao);
+    }
+
+    @Test
+    public void removeGroupWhenGroupNotExist() {
+
+        final ProjectDTO projectDTO = new ProjectDTO(
+                "name", Collections.emptySet(), "", "", null, Collections.emptyList(), true);
+        when(projectDAO.getProjectsWithEndpointStatusNotIn(UserInstanceStatus.TERMINATED,
+                UserInstanceStatus.TERMINATING)).thenReturn(Collections.singletonList(projectDTO));
+        when(userRoleDao.removeGroup(anyString())).thenReturn(false);
+        doNothing().when(userGroupDao).removeGroup(anyString());
+
+        userGroupService.removeGroup(getUserInfo(), GROUP);
+
+        verify(userRoleDao).removeGroup(GROUP);
+        verify(userGroupDao).removeGroup(GROUP);
+        verifyNoMoreInteractions(userGroupDao, userRoleDao);
+    }
+
+    @Test
+    public void removeGroupWithException() {
+        final ProjectDTO projectDTO = new ProjectDTO(
+                "name", Collections.emptySet(), "", "", null, Collections.emptyList(), true);
+        when(projectDAO.getProjectsWithEndpointStatusNotIn(UserInstanceStatus.TERMINATED,
+                UserInstanceStatus.TERMINATING)).thenReturn(Collections.singletonList(projectDTO));
+        when(userRoleDao.removeGroup(anyString())).thenThrow(new DatalabException("Exception"));
+
+        expectedException.expectMessage("Exception");
+        expectedException.expect(DatalabException.class);
+
+        userGroupService.removeGroup(getUserInfo(), GROUP);
+    }
+
+    private UserGroupDto getUserGroup() {
+        return new UserGroupDto(GROUP, Collections.emptyList(), Collections.emptySet());
+    }
+
+    private List<ProjectDTO> getProjects() {
+        return Collections.singletonList(ProjectDTO.builder()
+                .groups(new HashSet<>(Collections.singletonList(GROUP)))
+                .build());
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/util/CSVFormatterTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/util/CSVFormatterTest.java
new file mode 100644
index 0000000..34539a6
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/util/CSVFormatterTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.datalab.backendapi.util;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class CSVFormatterTest {
+
+    @Test
+    public void formatLine() {
+        List<String> values = Arrays.asList("aaa", "bbb", "ccc", "aa", "bb", "cc", "a", "b", "c");
+        String expected = "aaa,bbb,ccc,aa,bb,cc,a,b,c\n";
+        String actual = CSVFormatter.formatLine(values, ',');
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void formatLineWithCustomQuote() {
+        List<String> values = Arrays.asList("aaa", "bbb", "ccc", "aa", "bb", "cc", "a", "b", "c");
+        String expected = "\"aaa\",\"bbb\",\"ccc\",\"aa\",\"bb\",\"cc\",\"a\",\"b\",\"c\"\n";
+        String actual = CSVFormatter.formatLine(values, ',', '"');
+        assertEquals(expected, actual);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/util/DateRemoverUtilTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/util/DateRemoverUtilTest.java
new file mode 100644
index 0000000..59311e7
--- /dev/null
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/util/DateRemoverUtilTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datalab.backendapi.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class DateRemoverUtilTest {
+
+    @Test
+    public void removeDateFormErrorMessageWithErrorDateFormat() {
+        String errorMessage = "All dates with format '[Error-2018-04-12 15:30:35]:' are erroneous";
+        String expected = "All dates with format 'yyyy-MM-dd' are erroneous";
+        String actual = DateRemoverUtil.removeDateFormErrorMessage(errorMessage, "\\[Error-\\d{4}-\\d{2}-" +
+                "\\d{2} \\d{2}:\\d{2}:\\d{2}\\]:", "yyyy-MM-dd");
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void removeDateFormErrorMessage1() {
+        String errorMessage = "All dates with format '[Error-2018-04-12 15:30:35]:' are erroneous";
+        String expected = "All dates with format '[Error]:' are erroneous";
+        String actual = DateRemoverUtil.removeDateFormErrorMessage(errorMessage);
+        assertEquals(expected, actual);
+    }
+}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/domain/ExploratoryLibListTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/domain/ExploratoryLibListTest.java
deleted file mode 100644
index ee54306..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/domain/ExploratoryLibListTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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 com.epam.dlab.backendapi.resources.dto.LibraryAutoCompleteDTO;
-import org.junit.Test;
-
-import java.util.List;
-import java.util.Map;
-
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertFalse;
-import static junit.framework.TestCase.assertTrue;
-
-public class ExploratoryLibListTest {
-
-	@Test
-    public void getLibs() {
-		String content =
-				"{" +
-						"\"os_pkg\": {\"htop\": \"2.0.1-1ubuntu1\", \"python-mysqldb\": \"1.3.7-1build2\"}," +
-						"\"pip2\": {\"requests\": \"N/A\", \"configparser\": \"N/A\"}," +
-						"\"pip3\": {\"configparser\": \"N/A\"}," +
-						"\"r_pkg\": {\"rmarkdown\": \"1.5\"}" +
-						"}";
-
-		ExploratoryLibList libs = new ExploratoryLibList("imageName", content);
-
-		assertEquals("imageName", libs.getGroup());
-		assertFalse(libs.isExpired());
-		assertFalse(libs.isUpdateNeeded());
-		assertFalse(libs.isUpdating());
-
-		List<String> groups = libs.getGroupList();
-		assertEquals(4, groups.size());
-		assertEquals("os_pkg", groups.get(0));
-		assertEquals("r_pkg", groups.get(3));
-
-		Map<String, String> map = libs.getLibs("os_pkg");
-		assertEquals(2, map.size());
-		assertEquals("2.0.1-1ubuntu1", map.get("htop"));
-		assertEquals("1.3.7-1build2", map.get("python-mysqldb"));
-
-		final LibraryAutoCompleteDTO dtoList = libs.getLibs("os_pkg", "py");
-		assertEquals(1, dtoList.getLibraries().size());
-		assertEquals("1.3.7-1build2", dtoList.getLibraries().get(0).getVersion());
-
-		libs.setUpdating();
-		assertTrue(libs.isUpdating());
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ApplicationSettingResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ApplicationSettingResourceTest.java
deleted file mode 100644
index 9dd042e..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ApplicationSettingResourceTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.resources;
-
-
-import com.epam.dlab.backendapi.service.ApplicationSettingService;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Collections;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.*;
-
-public class ApplicationSettingResourceTest extends TestBase {
-
-	private ApplicationSettingService applicationSettingService = mock(ApplicationSettingService.class);
-
-	@Rule
-	public final ResourceTestRule resources =
-			getResourceTestRuleInstance(new ApplicationSettingResource(applicationSettingService));
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-
-	@Test
-	public void setMaxBudget() {
-		final Response response = resources.getJerseyTest()
-				.target("/settings/budget/12")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.put(Entity.entity("dummy", MediaType.TEXT_PLAIN));
-
-		assertEquals(HttpStatus.SC_NO_CONTENT, response.getStatus());
-
-		verify(applicationSettingService).setMaxBudget(12L);
-		verifyNoMoreInteractions(applicationSettingService);
-	}
-
-	@Test
-	public void removeMaxBudget() {
-		final Response response = resources.getJerseyTest()
-				.target("/settings/budget")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.delete();
-
-		assertEquals(HttpStatus.SC_NO_CONTENT, response.getStatus());
-
-		verify(applicationSettingService).removeMaxBudget();
-		verifyNoMoreInteractions(applicationSettingService);
-	}
-
-	@Test
-	public void getSettings() {
-
-		when(applicationSettingService.getSettings()).thenReturn(Collections.singletonMap("key", "value"));
-		final Response response = resources.getJerseyTest()
-				.target("/settings")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-		final Map map = response.readEntity(Map.class);
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getMediaType());
-		assertEquals(1, map.size());
-		assertEquals("value", map.get("key"));
-
-		verify(applicationSettingService).getSettings();
-		verifyNoMoreInteractions(applicationSettingService);
-
-
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/AuditResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/AuditResourceTest.java
deleted file mode 100644
index 185b260..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/AuditResourceTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.backendapi.domain.AuditCreateDTO;
-import com.epam.dlab.backendapi.domain.AuditResourceTypeEnum;
-import com.epam.dlab.backendapi.service.AuditService;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.eq;
-
-public class AuditResourceTest extends TestBase {
-
-    private final static String USER = "testuser";
-    private final static String INFO = "testInfo";
-    private final static String RESOURCE = "testResource";
-
-    private final AuditService auditService = mock(AuditService.class);
-
-    @Rule
-    public final ResourceTestRule resources = getResourceTestRuleInstance(new AuditResource(auditService));
-
-    @Before
-    public void setup() throws AuthenticationException {
-        authSetup();
-    }
-
-    @Test
-    public void saveAudit() {
-        final Response response = resources.getJerseyTest()
-                .target("/audit")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(prepareAuditCreateDTO()));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        verify(auditService).save(eq(USER), refEq(prepareAuditCreateDTO()));
-        verifyNoMoreInteractions(auditService);
-    }
-
-    @Test
-    public void getAudit() {
-        final Response response = resources.getJerseyTest()
-                .target("/audit")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-    }
-
-    private AuditCreateDTO prepareAuditCreateDTO() {
-        return new AuditCreateDTO(RESOURCE, INFO,AuditResourceTypeEnum.COMPUTE);
-    }
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/BackupResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/BackupResourceTest.java
deleted file mode 100644
index a5b6d1d..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/BackupResourceTest.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.resources.dto.BackupFormDTO;
-import com.epam.dlab.backendapi.resources.dto.BackupInfoRecord;
-import com.epam.dlab.backendapi.service.BackupService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.dto.backup.EnvBackupDTO;
-import com.epam.dlab.dto.backup.EnvBackupStatus;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.*;
-
-public class BackupResourceTest extends TestBase {
-
-	private final Date TIMESTAMP = new Date();
-	private BackupService backupService = mock(BackupService.class);
-	private RequestId requestId = mock(RequestId.class);
-	private RequestBuilder requestBuilder = mock(RequestBuilder.class);
-
-	@Rule
-	public final ResourceTestRule resources =
-			getResourceTestRuleInstance(new BackupResource(backupService, requestBuilder, requestId));
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-	@Test
-	public void getBackup() {
-		when(backupService.getBackup(anyString(), anyString())).thenReturn(getBackupInfo());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/backup/1")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(getBackupInfo(), response.readEntity(BackupInfoRecord.class));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(backupService).getBackup(USER.toLowerCase(), "1");
-		verifyNoMoreInteractions(backupService);
-		verifyZeroInteractions(requestId, requestBuilder);
-	}
-
-	@Test
-	public void getBackupWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		when(backupService.getBackup(anyString(), anyString())).thenReturn(getBackupInfo());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/backup/1")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verifyZeroInteractions(backupService, requestId, requestBuilder);
-	}
-
-	@Test
-	public void getBackupWithNotFoundException() {
-		when(backupService.getBackup(anyString(), anyString())).thenThrow(new ResourceNotFoundException("Backup not " +
-				"found"));
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/backup/1")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_NOT_FOUND, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(backupService).getBackup(USER.toLowerCase(), "1");
-		verifyNoMoreInteractions(backupService);
-		verifyZeroInteractions(requestId, requestBuilder);
-	}
-
-	@Test
-	public void getBackups() {
-		when(backupService.getBackups(anyString())).thenReturn(Collections.singletonList(getBackupInfo()));
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/backup")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(Collections.singletonList(getBackupInfo()),
-				response.readEntity(new GenericType<List<BackupInfoRecord>>() {
-				}));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(backupService).getBackups(USER.toLowerCase());
-		verifyNoMoreInteractions(backupService);
-		verifyZeroInteractions(requestId, requestBuilder);
-	}
-
-	@Test
-	public void getBackupsWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		when(backupService.getBackups(anyString())).thenReturn(Collections.singletonList(getBackupInfo()));
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/backup")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verifyZeroInteractions(backupService, requestId, requestBuilder);
-	}
-
-	@Test
-	public void createBackup() {
-		when(requestBuilder.newBackupCreate(any(BackupFormDTO.class), anyString())).thenReturn(getEnvBackupDto());
-		when(backupService.createBackup(any(EnvBackupDTO.class), any(UserInfo.class))).thenReturn("someUuid");
-		when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
-
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/backup")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json(getBackupFormDto()));
-
-		assertEquals(HttpStatus.SC_ACCEPTED, response.getStatus());
-		assertEquals(MediaType.TEXT_PLAIN, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(requestBuilder).newBackupCreate(eq(getBackupFormDto()), anyString());
-		verify(backupService).createBackup(getEnvBackupDto(), getUserInfo());
-		verify(requestId).put(USER.toLowerCase(), "someUuid");
-		verifyNoMoreInteractions(requestBuilder, backupService, requestId);
-	}
-
-	@Test
-	public void createBackupWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		when(requestBuilder.newBackupCreate(any(BackupFormDTO.class), anyString())).thenReturn(getEnvBackupDto());
-		when(backupService.createBackup(any(EnvBackupDTO.class), any(UserInfo.class))).thenReturn("someUuid");
-		when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
-
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/backup")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json(getBackupFormDto()));
-
-		assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verifyZeroInteractions(requestBuilder, backupService, requestId);
-	}
-
-	private BackupInfoRecord getBackupInfo() {
-		final List<String> configFiles = Arrays.asList("ss.yml", "sec.yml");
-		final List<String> keys = Collections.singletonList("key.pub");
-		final List<String> cert = Collections.singletonList("cert");
-		final List<String> jars = Collections.singletonList("ss.jar");
-		return new BackupInfoRecord(configFiles, keys, cert, jars, false, true, "file.backup",
-				EnvBackupStatus.CREATED, null, TIMESTAMP);
-	}
-
-	private BackupFormDTO getBackupFormDto() {
-		return new BackupFormDTO(Arrays.asList("ss.yml", "sec.yml"), Collections.singletonList("key.pub"),
-				Collections.singletonList("cert"), Collections.singletonList("ss.jar"), false, true);
-	}
-
-	private EnvBackupDTO getEnvBackupDto() {
-		return EnvBackupDTO.builder()
-				.configFiles(Arrays.asList("ss.yml", "sec.yml"))
-				.keys(Collections.singletonList("key.pub"))
-				.certificates(Collections.singletonList("cert"))
-				.jars(Collections.singletonList("ss.jar"))
-				.databaseBackup(false)
-				.logsBackup(true)
-				.backupFile("file.backup")
-				.id("someId")
-				.build();
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/EnvironmentResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/EnvironmentResourceTest.java
deleted file mode 100644
index 5ac537b..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/EnvironmentResourceTest.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.EnvironmentService;
-import com.epam.dlab.exceptions.ResourceConflictException;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class EnvironmentResourceTest extends TestBase {
-
-	private EnvironmentService environmentService = mock(EnvironmentService.class);
-
-	@Rule
-	public final ResourceTestRule resources = getResourceTestRuleInstance(new EnvironmentResource(environmentService));
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-	@Test
-	public void getAllEnv() {
-		UserInfo userInfo = getUserInfo();
-		when(environmentService.getAllEnv(userInfo)).thenReturn(Collections.emptyList());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/all")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(environmentService).getAllEnv(eq(userInfo));
-		verifyNoMoreInteractions(environmentService);
-	}
-
-	@Test
-	public void getAllEnvWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		when(environmentService.getAllEnv(getUserInfo())).thenReturn(Collections.emptyList());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/all")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verifyZeroInteractions(environmentService);
-	}
-
-	@Test
-	public void stopNotebook() {
-		doNothing().when(environmentService).stopExploratory(any(UserInfo.class), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/stop/projectName/explName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.text(USER));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(environmentService).stopExploratory(new UserInfo(USER, TOKEN), USER, "projectName", "explName");
-		verifyNoMoreInteractions(environmentService);
-	}
-
-	@Test
-	public void stopNotebookWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		doNothing().when(environmentService).stopExploratory(any(UserInfo.class), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/stop/projectName/explName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.text(USER));
-
-		assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verifyZeroInteractions(environmentService);
-	}
-
-	@Test
-	public void stopNotebookWithResourceConflictException() {
-		doThrow(new ResourceConflictException("Can not stop notebook because its status is CREATING or STARTING"))
-				.when(environmentService).stopExploratory(any(UserInfo.class), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/stop/projectName/explName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.text(USER));
-
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(environmentService).stopExploratory(new UserInfo(USER, TOKEN), USER, "projectName", "explName");
-		verifyNoMoreInteractions(environmentService);
-	}
-
-	@Test
-	public void stopCluster() {
-		doNothing().when(environmentService).stopComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/stop/projectName/explName/compName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.text(USER));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(environmentService).stopComputational(new UserInfo(USER, TOKEN), USER, "projectName", "explName", "compName");
-		verifyNoMoreInteractions(environmentService);
-	}
-
-	@Test
-	public void stopClusterWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		doNothing().when(environmentService).stopComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/stop/projectName/explName/compName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.text(USER));
-
-		assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verifyZeroInteractions(environmentService);
-	}
-
-	@Test
-	public void stopClusterWithResourceConflictException() {
-		doThrow(new ResourceConflictException("Can not stop cluster because its status is CREATING or STARTING"))
-				.when(environmentService).stopComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/stop/projectName/explName/compName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.text(USER));
-
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(environmentService).stopComputational(new UserInfo(USER, TOKEN), USER, "projectName", "explName", "compName");
-		verifyNoMoreInteractions(environmentService);
-	}
-
-	@Test
-	public void terminateNotebook() {
-		doNothing().when(environmentService).terminateExploratory(any(UserInfo.class), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/terminate/projectName/explName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.text(USER));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(environmentService).terminateExploratory(new UserInfo(USER, TOKEN), USER, "projectName", "explName");
-		verifyNoMoreInteractions(environmentService);
-	}
-
-	@Test
-	public void terminateNotebookWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		doNothing().when(environmentService).terminateExploratory(any(UserInfo.class), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/terminate/projectName/explName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.text(USER));
-
-		assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verifyZeroInteractions(environmentService);
-	}
-
-	@Test
-	public void terminateNotebookWithResourceConflictException() {
-		doThrow(new ResourceConflictException("Can not terminate notebook because its status is CREATING or STARTING"))
-				.when(environmentService).terminateExploratory(any(UserInfo.class), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/terminate/projectName/explName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.text(USER));
-
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(environmentService).terminateExploratory(new UserInfo(USER, TOKEN), USER, "projectName", "explName");
-		verifyNoMoreInteractions(environmentService);
-	}
-
-	@Test
-	public void terminateCluster() {
-		doNothing().when(environmentService).terminateComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/terminate/projectName/explName/compName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.text(USER));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(environmentService).terminateComputational(new UserInfo(USER, TOKEN), USER, "projectName", "explName", "compName");
-		verifyNoMoreInteractions(environmentService);
-	}
-
-	@Test
-	public void terminateClusterWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		doNothing().when(environmentService).terminateComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/terminate/projectName/explName/compName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.text(USER));
-
-		assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verifyZeroInteractions(environmentService);
-	}
-
-	@Test
-	public void terminateClusterWithResourceConflictException() {
-		doThrow(new ResourceConflictException("Can not terminate cluster because its status is CREATING or STARTING"))
-				.when(environmentService).terminateComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/environment/terminate/projectName/explName/compName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.text(USER));
-
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(environmentService).terminateComputational(new UserInfo(USER, TOKEN), USER, "projectName", "explName", "compName");
-		verifyNoMoreInteractions(environmentService);
-	}
-}
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
deleted file mode 100644
index b68ea11..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ExploratoryResourceTest.java
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.ExploratoryActionFormDTO;
-import com.epam.dlab.backendapi.resources.dto.ExploratoryCreateFormDTO;
-import com.epam.dlab.backendapi.service.ExploratoryService;
-import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.model.exploratory.Exploratory;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Collections;
-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.anyString;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class ExploratoryResourceTest extends TestBase {
-
-	private ExploratoryService exploratoryService = mock(ExploratoryService.class);
-
-	@Rule
-	public final ResourceTestRule resources = getResourceTestRuleInstance(new ExploratoryResource(exploratoryService));
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-	@Test
-	public void create() {
-        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(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment")
-				.request()
-                .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));
-
-        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(), anyString())).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));
-
-        verify(exploratoryService).start(getUserInfo(), exploratoryDTO.getNotebookInstanceName(), exploratoryDTO.getProjectName(), null);
-
-        verifyZeroInteractions(exploratoryService);
-    }
-
-	@Test
-	public void startUnprocessableEntity() {
-        when(exploratoryService.start(any(UserInfo.class), anyString(), 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_UNPROCESSABLE_ENTITY, 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(), anyString())).thenReturn("someUuid");
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/project/someName/stop")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .delete();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals("someUuid", response.readEntity(String.class));
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		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(), anyString(), anyString())).thenReturn("someUuid");
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/project/someName/stop")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .delete();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals("someUuid", response.readEntity(String.class));
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		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(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/project/someName/stop")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.delete();
-
-		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).stop(getUserInfo(), getUserInfo().getName(), "project", "someName", null);
-		verifyNoMoreInteractions(exploratoryService);
-	}
-
-	@Test
-	public void terminate() {
-        when(exploratoryService.terminate(any(UserInfo.class), anyString(), anyString(), anyString(), anyString())).thenReturn("someUuid");
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/project/someName/terminate")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .delete();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals("someUuid", response.readEntity(String.class));
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		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(), anyString(), anyString())).thenReturn("someUuid");
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/project/someName/terminate")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .delete();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals("someUuid", response.readEntity(String.class));
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		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(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/project/someName/terminate")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.delete();
-
-		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).terminate(getUserInfo(), getUserInfo().getName(), "project", "someName", null);
-		verifyNoMoreInteractions(exploratoryService);
-	}
-
-	@Test
-	public void updateSparkConfig() {
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/someProject/someName/reconfigure")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.put(Entity.json(Collections.singletonList(new ClusterConfig())));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-
-		verify(exploratoryService).updateClusterConfig(refEq(getUserInfo()), eq("someProject"),
-				eq("someName"), eq(Collections.singletonList(new ClusterConfig())));
-		verifyNoMoreInteractions(exploratoryService);
-	}
-
-	@Test
-	public void getSparkConfig() {
-		final ClusterConfig config = new ClusterConfig();
-		config.setClassification("test");
-		when(exploratoryService.getClusterConfig(any(UserInfo.class), anyString(), anyString())).thenReturn(Collections.singletonList(config));
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/someProject/someName/cluster/config")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		final List<ClusterConfig> clusterConfigs = response.readEntity(new GenericType<List<ClusterConfig>>() {
-		});
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(1, clusterConfigs.size());
-		assertEquals("test", clusterConfigs.get(0).getClassification());
-
-		verify(exploratoryService).getClusterConfig(refEq(getUserInfo()), eq("someProject"), eq("someName"));
-		verifyNoMoreInteractions(exploratoryService);
-	}
-
-	private ExploratoryCreateFormDTO getExploratoryCreateFormDTO() {
-		ExploratoryCreateFormDTO ecfDto = new ExploratoryCreateFormDTO();
-		ecfDto.setImage("someImage");
-		ecfDto.setTemplateName("someTemplateName");
-		ecfDto.setName("someName");
-		ecfDto.setShape("someShape");
-		ecfDto.setVersion("someVersion");
-		ecfDto.setImageName("someImageName");
-		ecfDto.setProject("project");
-		ecfDto.setEndpoint("endpoint");
-		return ecfDto;
-	}
-
-	private ExploratoryActionFormDTO getEmptyExploratoryActionFormDTO() {
-		return new ExploratoryActionFormDTO();
-	}
-
-	private ExploratoryActionFormDTO getExploratoryActionFormDTO() {
-		return new ExploratoryActionFormDTO("notebook_instance_name", "project_name");
-	}
-
-	private Exploratory getExploratory(@Valid @NotNull ExploratoryCreateFormDTO formDTO) {
-		return Exploratory.builder()
-				.name(formDTO.getName())
-				.dockerImage(formDTO.getImage())
-				.imageName(formDTO.getImageName())
-				.templateName(formDTO.getTemplateName())
-				.version(formDTO.getVersion())
-				.shape(formDTO.getShape())
-				.endpoint(formDTO.getEndpoint())
-				.project(formDTO.getProject()).build();
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/GitCredsResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/GitCredsResourceTest.java
deleted file mode 100644
index 8557792..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/GitCredsResourceTest.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.GitCredentialService;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCreds;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsDTO;
-import com.epam.dlab.exceptions.DlabException;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.*;
-
-public class GitCredsResourceTest extends TestBase {
-
-	private GitCredentialService gitCredentialService = mock(GitCredentialService.class);
-
-	@Rule
-	public final ResourceTestRule resources = getResourceTestRuleInstance(new GitCredsResource(gitCredentialService));
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-	@Test
-	public void updateGitCreds() {
-		doNothing().when(gitCredentialService).updateGitCredentials(any(UserInfo.class),
-				any(ExploratoryGitCredsDTO.class));
-		final Response response = resources.getJerseyTest()
-				.target("/user/git_creds")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.put(Entity.json(getExploratoryGitCredsDTO()));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(gitCredentialService)
-				.updateGitCredentials(refEq(getUserInfo()), refEq(getExploratoryGitCredsDTO(), "self"));
-		verifyNoMoreInteractions(gitCredentialService);
-	}
-
-	@Test
-	public void updateGitCredsWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		doNothing().when(gitCredentialService).updateGitCredentials(any(UserInfo.class),
-				any(ExploratoryGitCredsDTO.class));
-		final Response response = resources.getJerseyTest()
-				.target("/user/git_creds")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.put(Entity.json(getExploratoryGitCredsDTO()));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(gitCredentialService)
-				.updateGitCredentials(refEq(getUserInfo()), refEq(getExploratoryGitCredsDTO(), "self"));
-		verifyNoMoreInteractions(gitCredentialService);
-	}
-
-	@Test
-	public void updateGitCredsWithException() {
-		doThrow(new DlabException("Cannot update the GIT credentials")).when(gitCredentialService)
-				.updateGitCredentials(any(UserInfo.class), any(ExploratoryGitCredsDTO.class));
-		final Response response = resources.getJerseyTest()
-				.target("/user/git_creds")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.put(Entity.json(getExploratoryGitCredsDTO()));
-
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(gitCredentialService).updateGitCredentials(refEq(getUserInfo()),
-				refEq(getExploratoryGitCredsDTO(), "self"));
-		verifyNoMoreInteractions(gitCredentialService);
-	}
-
-	@Test
-	public void getGitCreds() {
-		ExploratoryGitCredsDTO egcDto = getExploratoryGitCredsDTO();
-		when(gitCredentialService.getGitCredentials(anyString())).thenReturn(egcDto);
-		final Response response = resources.getJerseyTest()
-				.target("/user/git_creds")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(egcDto.getGitCreds(), response.readEntity(ExploratoryGitCredsDTO.class).getGitCreds());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(gitCredentialService).getGitCredentials(USER.toLowerCase());
-		verifyNoMoreInteractions(gitCredentialService);
-	}
-
-	@Test
-	public void getGitCredsWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		ExploratoryGitCredsDTO egcDto = getExploratoryGitCredsDTO();
-		when(gitCredentialService.getGitCredentials(anyString())).thenReturn(egcDto);
-		final Response response = resources.getJerseyTest()
-				.target("/user/git_creds")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(egcDto.getGitCreds(), response.readEntity(ExploratoryGitCredsDTO.class).getGitCreds());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(gitCredentialService).getGitCredentials(USER.toLowerCase());
-		verifyNoMoreInteractions(gitCredentialService);
-	}
-
-	@Test
-	public void getGitCredsWithException() {
-		doThrow(new DlabException("Cannot load GIT credentials for user"))
-				.when(gitCredentialService).getGitCredentials(anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/user/git_creds")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(gitCredentialService).getGitCredentials(USER.toLowerCase());
-		verifyNoMoreInteractions(gitCredentialService);
-	}
-
-	private ExploratoryGitCredsDTO getExploratoryGitCredsDTO() {
-		ExploratoryGitCredsDTO exploratoryGitCredsDTO = new ExploratoryGitCredsDTO();
-		final ExploratoryGitCreds exploratoryGitCreds = new ExploratoryGitCreds();
-		exploratoryGitCreds.setHostname("host");
-		exploratoryGitCredsDTO.setGitCreds(Collections.singletonList(exploratoryGitCreds));
-		return exploratoryGitCredsDTO;
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ImageExploratoryResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ImageExploratoryResourceTest.java
deleted file mode 100644
index 7c065dc..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ImageExploratoryResourceTest.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.resources.dto.ExploratoryImageCreateFormDTO;
-import com.epam.dlab.backendapi.resources.dto.ImageInfoRecord;
-import com.epam.dlab.backendapi.service.ImageExploratoryService;
-import com.epam.dlab.dto.exploratory.ImageStatus;
-import com.epam.dlab.exceptions.ResourceAlreadyExistException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Collections;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class ImageExploratoryResourceTest extends TestBase {
-	private final static String AUDIT_MESSAGE = "Create image: %s";
-	private static final String PROJECT = "projectName";
-	private ImageExploratoryService imageExploratoryService = mock(ImageExploratoryService.class);
-	private RequestId requestId = mock(RequestId.class);
-
-	@Rule
-	public final ResourceTestRule resources =
-			getResourceTestRuleInstance(new ImageExploratoryResource(imageExploratoryService, requestId));
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-	@Test
-	public void createImage() {
-		when(imageExploratoryService.createImage(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString()))
-				.thenReturn("someUuid");
-		when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/image")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json(getExploratoryImageCreateFormDTO()));
-
-		assertEquals(HttpStatus.SC_ACCEPTED, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(imageExploratoryService).createImage(getUserInfo(), PROJECT, "someNotebookName",
-				"someImageName", "someDescription", String.format(AUDIT_MESSAGE, "someImageName"));
-		verify(requestId).put(USER.toLowerCase(), "someUuid");
-		verifyNoMoreInteractions(imageExploratoryService, requestId);
-	}
-
-	@Test
-	public void createImageWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		when(imageExploratoryService.createImage(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString()))
-				.thenReturn("someUuid");
-		when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/image")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json(getExploratoryImageCreateFormDTO()));
-
-		assertEquals(HttpStatus.SC_ACCEPTED, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(imageExploratoryService).createImage(getUserInfo(), PROJECT, "someNotebookName", "someImageName", "someDescription", String.format(AUDIT_MESSAGE, "someImageName"));
-
-		verify(requestId).put(USER.toLowerCase(), "someUuid");
-		verifyNoMoreInteractions(imageExploratoryService, requestId);
-	}
-
-	@Test
-	public void createImageWithException() {
-		doThrow(new ResourceAlreadyExistException("Image with name is already exist"))
-				.when(imageExploratoryService).createImage(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/image")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json(getExploratoryImageCreateFormDTO()));
-
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(imageExploratoryService).createImage(getUserInfo(), PROJECT, "someNotebookName", "someImageName", "someDescription", String.format(AUDIT_MESSAGE, "someImageName"));
-		verifyNoMoreInteractions(imageExploratoryService);
-		verifyZeroInteractions(requestId);
-	}
-
-	@Test
-	public void getImages() {
-		when(imageExploratoryService.getNotFailedImages(anyString(), anyString(), anyString(), anyString()))
-				.thenReturn(getImageList());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/image")
-				.queryParam("docker_image", "someDockerImage")
-				.queryParam("project", "someProject")
-				.queryParam("endpoint", "someEndpoint")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(getImageList(), response.readEntity(new GenericType<List<ImageInfoRecord>>() {
-		}));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(imageExploratoryService).getNotFailedImages(USER.toLowerCase(), "someDockerImage", "someProject", "someEndpoint");
-		verifyNoMoreInteractions(imageExploratoryService);
-	}
-
-	@Test
-	public void getImagesWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		when(imageExploratoryService.getNotFailedImages(anyString(), anyString(), anyString(), anyString()))
-				.thenReturn(getImageList());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/image")
-				.queryParam("docker_image", "someDockerImage")
-				.queryParam("project", "someProject")
-				.queryParam("endpoint", "someEndpoint")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(getImageList(), response.readEntity(new GenericType<List<ImageInfoRecord>>() {
-		}));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(imageExploratoryService).getNotFailedImages(USER.toLowerCase(), "someDockerImage", "someProject", "someEndpoint");
-		verifyNoMoreInteractions(imageExploratoryService);
-	}
-
-	@Test
-	public void getImage() {
-		when(imageExploratoryService.getImage(anyString(), anyString(), anyString(), anyString()))
-				.thenReturn(getImageList().get(0));
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/image/someName")
-				.queryParam("project", "someProject")
-				.queryParam("endpoint", "someEndpoint")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(getImageList().get(0), response.readEntity(ImageInfoRecord.class));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(imageExploratoryService).getImage(USER.toLowerCase(), "someName", "someProject", "someEndpoint");
-		verifyNoMoreInteractions(imageExploratoryService);
-	}
-
-	@Test
-	public void getImageWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		when(imageExploratoryService.getImage(anyString(), anyString(), anyString(), anyString()))
-				.thenReturn(getImageList().get(0));
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/image/someName")
-				.queryParam("project", "someProject")
-				.queryParam("endpoint", "someEndpoint")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(getImageList().get(0), response.readEntity(ImageInfoRecord.class));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(imageExploratoryService).getImage(USER.toLowerCase(), "someName", "someProject", "someEndpoint");
-		verifyNoMoreInteractions(imageExploratoryService);
-	}
-
-	@Test
-	public void getAllImagesForProject() {
-		when(imageExploratoryService.getImagesForProject(anyString())).thenReturn(getImageList());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/image/all")
-				.queryParam("project", "someProject")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(getImageList(), response.readEntity(new GenericType<List<ImageInfoRecord>>() {}));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(imageExploratoryService).getImagesForProject("someProject");
-		verifyNoMoreInteractions(imageExploratoryService);
-	}
-
-	@Test
-	public void getAllImagesForNullProject() {
-		when(imageExploratoryService.getImagesForProject(anyString())).thenReturn(getImageList());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/image/all")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(imageExploratoryService, never()).getImagesForProject(anyString());
-		verifyNoMoreInteractions(imageExploratoryService);
-	}
-
-	@Test
-	public void getImageWithException() {
-		doThrow(new ResourceNotFoundException("Image with name was not found for user"))
-				.when(imageExploratoryService).getImage(anyString(), anyString(), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/image/someName")
-				.queryParam("project", "someProject")
-				.queryParam("endpoint", "someEndpoint")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_NOT_FOUND, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(imageExploratoryService).getImage(USER.toLowerCase(), "someName", "someProject", "someEndpoint");
-		verifyNoMoreInteractions(imageExploratoryService);
-	}
-
-	private ExploratoryImageCreateFormDTO getExploratoryImageCreateFormDTO() {
-		ExploratoryImageCreateFormDTO eicfDto = new ExploratoryImageCreateFormDTO("someImageName", "someDescription");
-		eicfDto.setNotebookName("someNotebookName");
-		eicfDto.setProjectName(PROJECT);
-		return eicfDto;
-	}
-
-	private List<ImageInfoRecord> getImageList() {
-		ImageInfoRecord imageInfoRecord = new ImageInfoRecord("someName", "someDescription", "someProject", "someEndpoint", "someUser", "someApp",
-				"someFullName", ImageStatus.CREATED);
-		return Collections.singletonList(imageInfoRecord);
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResourceTest.java
deleted file mode 100644
index d6a150a..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResourceTest.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.HealthStatusPageDTO;
-import com.epam.dlab.backendapi.service.InfrastructureInfoService;
-import com.epam.dlab.dto.InfrastructureMetaInfoDTO;
-import com.epam.dlab.exceptions.DlabException;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class InfrastructureInfoResourceTest extends TestBase {
-
-	private InfrastructureInfoService infrastructureInfoService = mock(InfrastructureInfoService.class);
-
-	@Rule
-	public final ResourceTestRule resources =
-			getResourceTestRuleInstance(new InfrastructureInfoResource(infrastructureInfoService));
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-	@Test
-	public void status() {
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verifyZeroInteractions(infrastructureInfoService);
-	}
-
-	@Test
-	public void statusWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verifyZeroInteractions(infrastructureInfoService);
-	}
-
-	@Test
-	public void healthStatus() {
-		HealthStatusPageDTO hspDto = getHealthStatusPageDTO();
-		when(infrastructureInfoService.getHeathStatus(any(UserInfo.class))).thenReturn(hspDto);
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/status")
-				.queryParam("full", "1")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(hspDto.getStatus(), response.readEntity(HealthStatusPageDTO.class).getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(infrastructureInfoService).getHeathStatus(refEq(getUserInfo()));
-		verifyNoMoreInteractions(infrastructureInfoService);
-	}
-
-	@Test
-	public void healthStatusWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		HealthStatusPageDTO hspDto = getHealthStatusPageDTO();
-		when(infrastructureInfoService.getHeathStatus(any(UserInfo.class))).thenReturn(hspDto);
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/status")
-				.queryParam("full", "1")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(hspDto.getStatus(), response.readEntity(HealthStatusPageDTO.class).getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(infrastructureInfoService).getHeathStatus(refEq(getUserInfo()));
-		verifyNoMoreInteractions(infrastructureInfoService);
-	}
-
-	@Test
-	public void healthStatusWithDefaultQueryParam() {
-		HealthStatusPageDTO hspDto = getHealthStatusPageDTO();
-		when(infrastructureInfoService.getHeathStatus(any(UserInfo.class))).thenReturn(hspDto);
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/status")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(hspDto.getStatus(), response.readEntity(HealthStatusPageDTO.class).getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(infrastructureInfoService).getHeathStatus(refEq(getUserInfo()));
-		verifyNoMoreInteractions(infrastructureInfoService);
-	}
-
-	@Test
-	public void healthStatusWithException() {
-		doThrow(new DlabException("Could not return status of resources for user"))
-				.when(infrastructureInfoService).getHeathStatus(any(UserInfo.class));
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/status")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(infrastructureInfoService).getHeathStatus(refEq(getUserInfo()));
-		verifyNoMoreInteractions(infrastructureInfoService);
-	}
-
-
-	@Test
-	public void getUserResourcesWithException() {
-		doThrow(new DlabException("Could not load list of provisioned resources for user"))
-				.when(infrastructureInfoService).getUserResources(any(UserInfo.class));
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/info")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(infrastructureInfoService).getUserResources(any());
-		verifyNoMoreInteractions(infrastructureInfoService);
-	}
-
-	@Test
-	public void getInfrastructureMeta() {
-
-		when(infrastructureInfoService.getInfrastructureMetaInfo()).thenReturn(
-				InfrastructureMetaInfoDTO.builder()
-						.version("1.0").build());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure/meta")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		final InfrastructureMetaInfoDTO infrastructureMetaInfoDTO =
-				response.readEntity(InfrastructureMetaInfoDTO.class);
-		assertEquals("1.0", infrastructureMetaInfoDTO.getVersion());
-	}
-
-	private HealthStatusPageDTO getHealthStatusPageDTO() {
-		return HealthStatusPageDTO.builder()
-				.status("someStatus")
-				.build();
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResourceTest.java
deleted file mode 100644
index eeb6e06..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResourceTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.InfrastructureTemplateService;
-import com.epam.dlab.dto.base.computational.FullComputationalTemplate;
-import com.epam.dlab.dto.imagemetadata.ComputationalMetadataDTO;
-import com.epam.dlab.dto.imagemetadata.ExploratoryMetadataDTO;
-import com.epam.dlab.exceptions.DlabException;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Collections;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.*;
-
-public class InfrastructureTemplateResourceTest extends TestBase {
-
-	private InfrastructureTemplateService infrastructureTemplateService = mock(InfrastructureTemplateService.class);
-
-	@Rule
-	public final ResourceTestRule resources =
-			getResourceTestRuleInstance(new InfrastructureTemplateResource(infrastructureTemplateService));
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-	@Test
-	public void getComputationalTemplates() {
-		FullComputationalTemplate fullComputationalTemplate =
-				new FullComputationalTemplate(new ComputationalMetadataDTO());
-		when(infrastructureTemplateService.getComputationalTemplates(any(UserInfo.class), anyString(), anyString()))
-				.thenReturn(Collections.singletonList(fullComputationalTemplate));
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/test/endpoint/computational_templates")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test", "endpoint");
-		verifyNoMoreInteractions(infrastructureTemplateService);
-	}
-
-	@Test
-	public void getComputationalTemplatesWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		FullComputationalTemplate fullComputationalTemplate =
-				new FullComputationalTemplate(new ComputationalMetadataDTO());
-		when(infrastructureTemplateService.getComputationalTemplates(any(UserInfo.class), anyString(), anyString()))
-				.thenReturn(Collections.singletonList(fullComputationalTemplate));
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/test/endpoint/computational_templates")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test", "endpoint");
-		verifyNoMoreInteractions(infrastructureTemplateService);
-	}
-
-	@Test
-	public void getComputationalTemplatesWithException() {
-		doThrow(new DlabException("Could not load list of computational templates for user"))
-				.when(infrastructureTemplateService).getComputationalTemplates(any(UserInfo.class), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/test/endpoint/computational_templates")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test", "endpoint");
-		verifyNoMoreInteractions(infrastructureTemplateService);
-	}
-
-	@Test
-	public void getExploratoryTemplates() {
-		ExploratoryMetadataDTO exploratoryMetadataDTO =
-				new ExploratoryMetadataDTO("someImageName");
-		when(infrastructureTemplateService.getExploratoryTemplates(any(UserInfo.class), anyString(), anyString()))
-				.thenReturn(Collections.singletonList(exploratoryMetadataDTO));
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/test/endpoint/exploratory_templates")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(Collections.singletonList(exploratoryMetadataDTO),
-				response.readEntity(new GenericType<List<ExploratoryMetadataDTO>>() {
-				}));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test", "endpoint");
-		verifyNoMoreInteractions(infrastructureTemplateService);
-	}
-
-	@Test
-	public void getExploratoryTemplatesWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		ExploratoryMetadataDTO exploratoryMetadataDTO =
-				new ExploratoryMetadataDTO("someImageName");
-		when(infrastructureTemplateService.getExploratoryTemplates(any(UserInfo.class), anyString(), anyString()))
-				.thenReturn(Collections.singletonList(exploratoryMetadataDTO));
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/test/endpoint/exploratory_templates")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(Collections.singletonList(exploratoryMetadataDTO),
-				response.readEntity(new GenericType<List<ExploratoryMetadataDTO>>() {
-				}));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test", "endpoint");
-		verifyNoMoreInteractions(infrastructureTemplateService);
-	}
-
-
-	@Test
-	public void getExploratoryTemplatesWithException() {
-		doThrow(new DlabException("Could not load list of exploratory templates for user"))
-				.when(infrastructureTemplateService).getExploratoryTemplates(any(UserInfo.class), anyString(), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/test/endpoint/exploratory_templates")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test", "endpoint");
-		verifyNoMoreInteractions(infrastructureTemplateService);
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/KeycloakResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/KeycloakResourceTest.java
deleted file mode 100644
index 31ea3a3..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/KeycloakResourceTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.SecurityDAO;
-import com.epam.dlab.backendapi.service.KeycloakService;
-import com.epam.dlab.backendapi.service.SecurityService;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Rule;
-import org.junit.Test;
-import org.keycloak.representations.AccessTokenResponse;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-public class KeycloakResourceTest extends TestBase {
-    private SecurityService securityService = mock(SecurityService.class);
-    private SelfServiceApplicationConfiguration configuration = mock(SelfServiceApplicationConfiguration.class, RETURNS_DEEP_STUBS);
-    private SecurityDAO securityDAO = mock(SecurityDAO.class);
-    private KeycloakService keycloakService = mock(KeycloakService.class);
-
-    @Rule
-    public final ResourceTestRule resources = getResourceTestRuleInstance(
-            new KeycloakResource(securityService, configuration, securityDAO, keycloakService));
-
-    @Test
-    public void refreshAccessToken() {
-        when(keycloakService.generateAccessToken(anyString())).thenReturn(mock(AccessTokenResponse.class));
-
-        final Response response = resources.getJerseyTest()
-                .target("oauth/refresh/" + "refresh_token")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(""));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-        verify(keycloakService).generateAccessToken(anyString());
-        verifyNoMoreInteractions(keycloakService);
-    }
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/LibExploratoryResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/LibExploratoryResourceTest.java
deleted file mode 100644
index 419acbf..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/LibExploratoryResourceTest.java
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.resources.dto.LibInfoRecord;
-import com.epam.dlab.backendapi.resources.dto.LibInstallFormDTO;
-import com.epam.dlab.backendapi.resources.dto.LibKey;
-import com.epam.dlab.backendapi.resources.dto.LibraryDTO;
-import com.epam.dlab.backendapi.resources.dto.LibraryStatus;
-import com.epam.dlab.backendapi.resources.dto.SearchLibsFormDTO;
-import com.epam.dlab.backendapi.service.ExternalLibraryService;
-import com.epam.dlab.backendapi.service.LibraryService;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.dto.exploratory.LibInstallDTO;
-import com.epam.dlab.dto.exploratory.LibraryInstallDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.bson.Document;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static java.util.Collections.singletonList;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.anyListOf;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class LibExploratoryResourceTest extends TestBase {
-    private static final String AUDIT_MESSAGE = "Install libs: %s";
-    private static final String LIB_GROUP = "group";
-    private static final String LIB_NAME = "name";
-    private static final String LIB_VERSION = "version";
-    private static final String EXPLORATORY_NAME = "explName";
-    private static final String PROJECT = "projectName";
-    private static final String COMPUTATIONAL_NAME = "compName";
-    private static final String UUID = "uid";
-    private ExploratoryDAO exploratoryDAO = mock(ExploratoryDAO.class);
-    private LibraryService libraryService = mock(LibraryService.class);
-    private RESTService provisioningService = mock(RESTService.class);
-    private ExternalLibraryService externalLibraryService = mock(ExternalLibraryService.class);
-    private RequestId requestId = mock(RequestId.class);
-
-    @Rule
-    public final ResourceTestRule resources = getResourceTestRuleInstance(
-            new LibExploratoryResource(exploratoryDAO, libraryService, externalLibraryService));
-
-    @Before
-    public void setup() throws AuthenticationException {
-        authSetup();
-    }
-
-	@Test
-	public void getComputeLibGroupList() {
-		when(libraryService.getComputeLibGroups()).thenReturn(Collections.emptyList());
-
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/lib-groups/compute")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(libraryService).getComputeLibGroups();
-		verifyNoMoreInteractions(libraryService);
-	}
-
-	@Test
-	public void getExploratoryLibGroupList() {
-		when(libraryService.getExploratoryLibGroups(any(UserInfo.class), anyString(), anyString())).thenReturn(Collections.emptyList());
-
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/lib-groups/exploratory")
-				.queryParam("project", "projectName")
-				.queryParam("exploratory", "explName")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(libraryService).getExploratoryLibGroups(getUserInfo(), "projectName", "explName");
-		verifyNoMoreInteractions(libraryService);
-	}
-
-	@Test
-	public void getLibList() {
-        when(libraryService.getLibs(anyString(), anyString(), anyString(), anyString())).thenReturn(getDocuments());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/lib_list")
-                .queryParam("project_name", "projectName")
-                .queryParam("exploratory_name", "explName")
-                .queryParam("computational_name", "compName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(getDocuments(), response.readEntity(new GenericType<List<Document>>() {
-        }));
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(libraryService).getLibs(USER.toLowerCase(), "projectName", "explName", "compName");
-        verifyNoMoreInteractions(libraryService);
-    }
-
-	@Test
-	public void getLibListWithFailedAuth() throws AuthenticationException {
-        authFailSetup();
-        when(libraryService.getLibs(anyString(), anyString(), anyString(), anyString())).thenReturn(getDocuments());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/lib_list")
-                .queryParam("project_name", "projectName")
-                .queryParam("exploratory_name", "explName")
-                .queryParam("computational_name", "compName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(getDocuments(), response.readEntity(new GenericType<List<Document>>() {
-        }));
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(libraryService).getLibs(USER.toLowerCase(), "projectName", "explName", "compName");
-        verifyNoMoreInteractions(libraryService);
-    }
-
-	@Test
-	public void getLibListWithException() {
-        doThrow(new DlabException("Cannot load installed libraries"))
-                .when(libraryService).getLibs(anyString(), anyString(), anyString(), anyString());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/lib_list")
-                .queryParam("project_name", "projectName")
-                .queryParam("exploratory_name", "explName")
-                .queryParam("computational_name", "compName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(libraryService).getLibs(USER.toLowerCase(), "projectName", "explName", "compName");
-        verifyNoMoreInteractions(libraryService);
-    }
-
-	@Test
-	public void getLibListFormatted() {
-        when(libraryService.getLibInfo(anyString(), anyString(), anyString())).thenReturn(getLibInfoRecords());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/lib_list/formatted")
-                .queryParam("exploratory_name", "explName")
-                .queryParam("project_name", "projectName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(libraryService).getLibInfo(USER.toLowerCase(), "projectName", "explName");
-        verifyNoMoreInteractions(libraryService);
-    }
-
-	@Test
-	public void getLibListFormattedWithFailedAuth() throws AuthenticationException {
-        authFailSetup();
-        when(libraryService.getLibInfo(anyString(), anyString(), anyString())).thenReturn(getLibInfoRecords());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/lib_list/formatted")
-                .queryParam("exploratory_name", "explName")
-                .queryParam("project_name", "projectName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(libraryService).getLibInfo(USER.toLowerCase(), "projectName", "explName");
-        verifyNoMoreInteractions(libraryService);
-    }
-
-	@Test
-	public void getLibListFormattedWithException() {
-        doThrow(new DlabException("Cannot load  formatted list of installed libraries"))
-                .when(libraryService).getLibInfo(anyString(), anyString(), anyString());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/lib_list/formatted")
-                .queryParam("exploratory_name", "explName")
-                .queryParam("project_name", "projectName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(libraryService).getLibInfo(USER.toLowerCase(), "projectName", "explName");
-        verifyNoMoreInteractions(libraryService);
-    }
-
-	@Test
-	public void libInstall() {
-        List<LibInstallDTO> libInstallDTOS = singletonList(new LibInstallDTO(LIB_GROUP, LIB_NAME, LIB_VERSION));
-        when(libraryService.installComputationalLibs(any(UserInfo.class), anyString(), anyString(),
-                anyString(), anyListOf(LibInstallDTO.class), anyString())).thenReturn(UUID);
-        LibInstallFormDTO libInstallFormDTO = new LibInstallFormDTO();
-        libInstallFormDTO.setComputationalName(COMPUTATIONAL_NAME);
-        libInstallFormDTO.setNotebookName(EXPLORATORY_NAME);
-        libInstallFormDTO.setProject(PROJECT);
-        libInstallFormDTO.setLibs(libInstallDTOS);
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/lib_install")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(libInstallFormDTO));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-        assertEquals(UUID, response.readEntity(String.class));
-
-        verify(libraryService).installComputationalLibs(refEq(getUserInfo()), eq(PROJECT),
-                eq(EXPLORATORY_NAME), eq(COMPUTATIONAL_NAME), eq(libInstallDTOS), eq(getAuditInfo(libInstallDTOS)));
-        verifyNoMoreInteractions(libraryService);
-        verifyZeroInteractions(provisioningService, requestId);
-    }
-
-
-	@Test
-	public void libInstallWithoutComputational() {
-        List<LibInstallDTO> libInstallDTOS = singletonList(new LibInstallDTO(LIB_GROUP, LIB_NAME, LIB_VERSION));
-        when(libraryService.installExploratoryLibs(any(UserInfo.class), anyString(), anyString(), anyListOf(LibInstallDTO.class), anyString())).thenReturn(UUID);
-        LibInstallFormDTO libInstallFormDTO = new LibInstallFormDTO();
-        libInstallFormDTO.setNotebookName(EXPLORATORY_NAME);
-        libInstallFormDTO.setLibs(libInstallDTOS);
-        libInstallFormDTO.setProject(PROJECT);
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/lib_install")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(libInstallFormDTO));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-        assertEquals(UUID, response.readEntity(String.class));
-
-        verify(libraryService).installExploratoryLibs(refEq(getUserInfo()), eq(PROJECT),
-                eq(EXPLORATORY_NAME), eq(libInstallDTOS), eq(getAuditInfo(libInstallDTOS)));
-        verifyNoMoreInteractions(libraryService);
-        verifyZeroInteractions(provisioningService, requestId);
-    }
-
-	@Test
-	public void getLibraryListWithFailedAuth() throws AuthenticationException {
-        authFailSetup();
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyString()))
-                .thenReturn(getUserInstanceDto());
-        SearchLibsFormDTO searchLibsFormDTO = new SearchLibsFormDTO();
-        searchLibsFormDTO.setComputationalName("compName");
-        searchLibsFormDTO.setNotebookName("explName");
-        searchLibsFormDTO.setGroup("someGroup");
-        searchLibsFormDTO.setStartWith("someText");
-        searchLibsFormDTO.setProjectName("projectName");
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/search/lib_list")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(searchLibsFormDTO));
-
-        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER.toLowerCase(), "projectName", "explName", "compName");
-        verifyNoMoreInteractions(exploratoryDAO);
-    }
-
-	@Test
-	public void getLibraryListWithException() {
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyString()))
-                .thenReturn(getUserInstanceDto());
-        SearchLibsFormDTO searchLibsFormDTO = new SearchLibsFormDTO();
-        searchLibsFormDTO.setComputationalName("compName");
-        searchLibsFormDTO.setNotebookName("explName");
-        searchLibsFormDTO.setGroup("someGroup");
-        searchLibsFormDTO.setStartWith("someText");
-        searchLibsFormDTO.setProjectName("projectName");
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/search/lib_list")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(searchLibsFormDTO));
-
-        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER.toLowerCase(), "projectName", "explName", "compName");
-        verifyNoMoreInteractions(exploratoryDAO);
-    }
-
-	@Test
-	public void getLibraryListWithoutComputationalWithException() {
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString()))
-                .thenReturn(getUserInstanceDto());
-        SearchLibsFormDTO searchLibsFormDTO = new SearchLibsFormDTO();
-        searchLibsFormDTO.setComputationalName("");
-        searchLibsFormDTO.setNotebookName("explName");
-        searchLibsFormDTO.setGroup("someGroup");
-        searchLibsFormDTO.setStartWith("someText");
-        searchLibsFormDTO.setProjectName("projectName");
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/search/lib_list")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(searchLibsFormDTO));
-
-        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER.toLowerCase(), "projectName", "explName");
-        verifyNoMoreInteractions(exploratoryDAO);
-    }
-
-	@Test
-	public void getMavenArtifact() {
-		when(externalLibraryService.getLibrary(anyString(), anyString(), anyString())).thenReturn(libraryDto());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/search/lib_list/maven")
-				.queryParam("artifact", "group:artifact:version")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-		final LibraryDTO libraryDTO = response.readEntity(LibraryDTO.class);
-		assertEquals("test", libraryDTO.getName());
-		assertEquals("1.0", libraryDTO.getVersion());
-
-		verify(externalLibraryService).getLibrary("group", "artifact", "version");
-		verifyNoMoreInteractions(externalLibraryService);
-	}
-
-	@Test
-	public void getMavenArtifactWithValidationException() {
-		when(externalLibraryService.getLibrary(anyString(), anyString(), anyString())).thenReturn(libraryDto());
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/search/lib_list/maven")
-				.queryParam("artifact", "group:artifact")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		assertEquals("{\"errors\":[\"query param artifact Wrong library name format. Should be <groupId>:<artifactId>:<versionId>\"]}",
-				response.readEntity(String.class));
-
-		verifyZeroInteractions(externalLibraryService);
-	}
-
-	private LibraryDTO libraryDto() {
-		return new LibraryDTO(
-				"test", "1.0");
-	}
-
-    private UserInstanceDTO getUserInstanceDto() {
-        UserComputationalResource ucResource = new UserComputationalResource();
-        ucResource.setComputationalName("compName");
-        return new UserInstanceDTO()
-                .withUser(USER)
-                .withExploratoryName("explName")
-                .withProject(PROJECT)
-                .withResources(singletonList(ucResource));
-    }
-
-    private List<Document> getDocuments() {
-        return singletonList(new Document());
-    }
-
-    private List<LibInfoRecord> getLibInfoRecords() {
-        return singletonList(new LibInfoRecord(
-                new LibKey(), singletonList(new LibraryStatus())));
-    }
-
-    private LibraryInstallDTO getLibraryInstallDTO() {
-        return new LibraryInstallDTO().withComputationalName("compName");
-    }
-
-    private String getAuditInfo(List<LibInstallDTO> libs) {
-        return String.format(AUDIT_MESSAGE, libs
-                .stream()
-                .map(LibInstallDTO::getName)
-                .collect(Collectors.joining(", ")));
-    }
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ProjectResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ProjectResourceTest.java
deleted file mode 100644
index 43551ca..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ProjectResourceTest.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.BudgetDTO;
-import com.epam.dlab.backendapi.domain.CreateProjectDTO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.domain.ProjectEndpointDTO;
-import com.epam.dlab.backendapi.domain.UpdateProjectDTO;
-import com.epam.dlab.backendapi.domain.UpdateProjectBudgetDTO;
-import com.epam.dlab.backendapi.resources.dto.KeysDTO;
-import com.epam.dlab.backendapi.resources.dto.ProjectActionFormDTO;
-import com.epam.dlab.backendapi.service.AccessKeyService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceConflictException;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.anyList;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.doNothing;
-
-public class ProjectResourceTest extends TestBase {
-
-    private static final String PROJECT_NAME = "DLAB";
-
-    private final ProjectService projectService = mock(ProjectService.class);
-    private final AccessKeyService keyService = mock(AccessKeyService.class);
-
-    @Rule
-    public final ResourceTestRule resources = getResourceTestRuleInstance(
-            new ProjectResource(projectService, keyService));
-
-    @Before
-    public void setup() throws AuthenticationException {
-        authSetup();
-    }
-
-    @Test
-    public void createProject() {
-        CreateProjectDTO createProjectDTO = returnCreateProjectDTO();
-        final Response response = resources.getJerseyTest()
-                .target("project")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(createProjectDTO));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        verify(projectService).create(getUserInfo(), prepareProjectDTO(createProjectDTO), createProjectDTO.getName());
-        verifyNoMoreInteractions(projectService);
-    }
-
-    @Test
-    public void createExistingProject() {
-        CreateProjectDTO createProjectDTO = returnCreateProjectDTO();
-        doThrow(new ResourceConflictException("Project with passed name already exist in system"))
-                .when(projectService).create(any(UserInfo.class), any(ProjectDTO.class), anyString());
-        final Response response = resources.getJerseyTest()
-                .target("project")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(createProjectDTO));
-
-        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-        verify(projectService).create(getUserInfo(), prepareProjectDTO(createProjectDTO), createProjectDTO.getName());
-        verifyNoMoreInteractions(projectService);
-    }
-
-    @Test
-    public void startProject() {
-        final Response response = resources.getJerseyTest()
-                .target("project/start")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(getProjectActionDTO()));
-
-        assertEquals(HttpStatus.SC_ACCEPTED, response.getStatus());
-        verify(projectService).start(getUserInfo(), Collections.singletonList("https://localhost:8083/"), PROJECT_NAME);
-        verifyNoMoreInteractions(projectService);
-    }
-
-    @Test
-    public void stopProject() {
-        final Response response = resources.getJerseyTest()
-                .target("project/stop")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(getProjectActionDTO()));
-
-        assertEquals(HttpStatus.SC_ACCEPTED, response.getStatus());
-        verify(projectService).stopWithResources(getUserInfo(), Collections.singletonList("https://localhost:8083/"), PROJECT_NAME);
-        verifyNoMoreInteractions(projectService);
-    }
-
-    @Test
-    public void getProject() {
-        when(projectService.get(anyString())).thenReturn(ProjectDTO.builder().name(PROJECT_NAME).build());
-
-        final Response response = resources.getJerseyTest()
-                .target("project/" + PROJECT_NAME)
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-        verify(projectService).get(PROJECT_NAME);
-        verifyNoMoreInteractions(projectService);
-    }
-
-    @Test
-    public void getProjects() {
-        when(projectService.getProjects(any(UserInfo.class))).thenReturn(Collections.singletonList(ProjectDTO.builder().name(PROJECT_NAME).build()));
-
-        final Response response = resources.getJerseyTest()
-                .target("project")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-        verify(projectService).getProjects(getUserInfo());
-        verifyNoMoreInteractions(projectService);
-    }
-
-    @Test
-    public void getUserProjects() {
-        when(projectService.getUserProjects(getUserInfo(), false)).thenReturn(Collections.singletonList(ProjectDTO.builder().name(PROJECT_NAME).build()));
-
-        final Response response = resources.getJerseyTest()
-                .target("project/me")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-        verify(projectService).getUserProjects(getUserInfo(), Boolean.FALSE);
-        verifyNoMoreInteractions(projectService);
-    }
-
-    @Test
-    public void updateProject() {
-        doNothing().when(projectService).update(any(UserInfo.class), any(UpdateProjectDTO.class), anyString());
-
-        final Response response = resources.getJerseyTest()
-                .target("project")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .put(Entity.json(prepareUpdateProjectDTO()));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        verify(projectService).update(getUserInfo(), prepareUpdateProjectDTO(), PROJECT_NAME);
-        verifyNoMoreInteractions(projectService);
-    }
-
-    @Test
-    public void removeProjectEndpoint() {
-        doNothing().when(projectService).terminateEndpoint(any(UserInfo.class), anyList(), anyString());
-
-        final Response response = resources.getJerseyTest()
-                .target("project/terminate")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(prepareProjectActionFormDTO()));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        verify(projectService).terminateEndpoint(getUserInfo(), prepareProjectActionFormDTO().getEndpoints(), prepareProjectActionFormDTO().getProjectName());
-        verifyNoMoreInteractions(projectService);
-    }
-
-    @Test
-    public void updateBudget() {
-        doNothing().when(projectService).updateBudget(any(UserInfo.class), anyList());
-
-        final Response response = resources.getJerseyTest()
-                .target("project/budget")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .put(Entity.json((prepareUpdateProjectBudgetDTOs())));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-
-        verify(projectService).updateBudget(getUserInfo(), prepareUpdateProjectBudgetDTOs());
-        verifyNoMoreInteractions(projectService);
-    }
-
-    @Test
-    public void generate() {
-        when(keyService.generateKeys(any(UserInfo.class))).thenReturn(new KeysDTO("somePublicKey", "somePrivateKey", "user"));
-
-        final Response response = resources.getJerseyTest()
-                .target("/project/keys")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(""));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(keyService).generateKeys(getUserInfo());
-        verifyNoMoreInteractions(keyService);
-    }
-
-    @Test
-    public void generateKeysWithException() {
-        doThrow(new DlabException("Can not generate private/public key pair due to"))
-                .when(keyService).generateKeys(any(UserInfo.class));
-
-        final Response response = resources.getJerseyTest()
-                .target("/project/keys")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(""));
-
-        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(keyService).generateKeys(getUserInfo());
-        verifyNoMoreInteractions(keyService);
-    }
-
-    private CreateProjectDTO returnCreateProjectDTO() {
-        return new CreateProjectDTO(PROJECT_NAME, Collections.emptySet(), Collections.emptySet(), "ssh-testKey", "testTag");
-    }
-
-    private ProjectDTO prepareProjectDTO(CreateProjectDTO createProjectDTO) {
-        List<ProjectEndpointDTO> projectEndpointDTOS = createProjectDTO.getEndpoints()
-                .stream()
-                .map(e -> new ProjectEndpointDTO(e, UserInstanceStatus.CREATING, null))
-                .collect(Collectors.toList());
-
-        return new ProjectDTO(createProjectDTO.getName(), createProjectDTO.getGroups(), createProjectDTO.getKey(), createProjectDTO.getTag(),
-                new BudgetDTO(), projectEndpointDTOS, createProjectDTO.isSharedImageEnabled());
-    }
-
-    private ProjectActionFormDTO getProjectActionDTO() {
-        return new ProjectActionFormDTO(PROJECT_NAME, Collections.singletonList("https://localhost:8083/"));
-    }
-
-    private UpdateProjectDTO prepareUpdateProjectDTO() {
-        return new UpdateProjectDTO(PROJECT_NAME, Collections.emptySet(), Collections.emptySet(), Boolean.TRUE);
-    }
-
-    private ProjectActionFormDTO prepareProjectActionFormDTO(){
-        return new ProjectActionFormDTO(PROJECT_NAME, Collections.singletonList("https://localhost:8083/"));
-    }
-
-    private List<UpdateProjectBudgetDTO> prepareUpdateProjectBudgetDTOs() {
-        return Collections.singletonList(new UpdateProjectBudgetDTO(PROJECT_NAME, 123, Boolean.FALSE));
-    }
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/SchedulerJobResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/SchedulerJobResourceTest.java
deleted file mode 100644
index 994564d..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/SchedulerJobResourceTest.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.service.SchedulerJobService;
-import com.epam.dlab.dto.SchedulerJobDTO;
-import com.epam.dlab.exceptions.ResourceInappropriateStateException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.model.scheduler.SchedulerJobData;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.time.DayOfWeek;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.OffsetDateTime;
-import java.time.ZoneId;
-import java.time.temporal.ChronoUnit;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.anyLong;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-public class SchedulerJobResourceTest extends TestBase {
-
-	private SchedulerJobService schedulerJobService = mock(SchedulerJobService.class);
-
-	@Rule
-	public final ResourceTestRule resources =
-			getResourceTestRuleInstance(new SchedulerJobResource(schedulerJobService));
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-	@Test
-	public void updateExploratoryScheduler() {
-        doNothing().when(schedulerJobService)
-                .updateExploratorySchedulerData(any(UserInfo.class), anyString(), anyString(), any(SchedulerJobDTO.class));
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(getSchedulerJobDTO()));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(schedulerJobService).updateExploratorySchedulerData(getUserInfo(), "projectName",
-                "explName", getSchedulerJobDTO());
-        verifyNoMoreInteractions(schedulerJobService);
-    }
-
-	@Test
-	public void updateExploratorySchedulerWithFailedAuth() throws AuthenticationException {
-        authFailSetup();
-        doNothing().when(schedulerJobService)
-                .updateExploratorySchedulerData(any(UserInfo.class), anyString(), anyString(), any(SchedulerJobDTO.class));
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName")
-                .request()
-                .header("Authorization", String.join(" ", "Bearer", TOKEN))
-                .post(Entity.json(getSchedulerJobDTO()));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(schedulerJobService).updateExploratorySchedulerData(getUserInfo(), "projectName",
-                "explName", getSchedulerJobDTO());
-        verifyNoMoreInteractions(schedulerJobService);
-    }
-
-	@Test
-	public void updateExploratorySchedulerWithException() {
-        doThrow(new ResourceInappropriateStateException("Can't create/update scheduler for user instance with status"))
-                .when(schedulerJobService).updateExploratorySchedulerData(any(UserInfo.class), anyString(), anyString(),
-                any(SchedulerJobDTO.class));
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(getSchedulerJobDTO()));
-
-        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(schedulerJobService).updateExploratorySchedulerData(getUserInfo(), "projectName",
-                "explName", getSchedulerJobDTO());
-        verifyNoMoreInteractions(schedulerJobService);
-    }
-
-	@Test
-	public void upsertComputationalScheduler() {
-        doNothing().when(schedulerJobService)
-                .updateComputationalSchedulerData(any(UserInfo.class), anyString(), anyString(), anyString(), any(SchedulerJobDTO.class));
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName/compName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(getSchedulerJobDTO()));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(schedulerJobService).updateComputationalSchedulerData(getUserInfo(), "projectName",
-                "explName", "compName", getSchedulerJobDTO());
-        verifyNoMoreInteractions(schedulerJobService);
-    }
-
-	@Test
-	public void upsertComputationalSchedulerWithFailedAuth() throws AuthenticationException {
-        authFailSetup();
-        doNothing().when(schedulerJobService)
-                .updateComputationalSchedulerData(any(UserInfo.class), anyString(), anyString(), anyString(), any(SchedulerJobDTO.class));
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName/compName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(getSchedulerJobDTO()));
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(schedulerJobService).updateComputationalSchedulerData(getUserInfo(), "projectName",
-                "explName", "compName", getSchedulerJobDTO());
-        verifyNoMoreInteractions(schedulerJobService);
-    }
-
-	@Test
-	public void upsertComputationalSchedulerWithException() {
-        doThrow(new ResourceInappropriateStateException("Can't create/update scheduler for user instance with status"))
-                .when(schedulerJobService).updateComputationalSchedulerData(any(UserInfo.class), anyString(), anyString(),
-                anyString(), any(SchedulerJobDTO.class));
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName/compName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .post(Entity.json(getSchedulerJobDTO()));
-
-        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(schedulerJobService).updateComputationalSchedulerData(getUserInfo(), "projectName",
-                "explName", "compName", getSchedulerJobDTO());
-        verifyNoMoreInteractions(schedulerJobService);
-    }
-
-	@Test
-	public void fetchSchedulerJobForUserAndExploratory() {
-        when(schedulerJobService.fetchSchedulerJobForUserAndExploratory(anyString(), anyString(), anyString()))
-                .thenReturn(getSchedulerJobDTO());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(getSchedulerJobDTO(), response.readEntity(SchedulerJobDTO.class));
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(schedulerJobService).fetchSchedulerJobForUserAndExploratory(USER.toLowerCase(), "projectName", "explName");
-        verifyNoMoreInteractions(schedulerJobService);
-    }
-
-	@Test
-	public void fetchSchedulerJobForUserAndExploratoryWithFailedAuth() throws AuthenticationException {
-        authFailSetup();
-        when(schedulerJobService.fetchSchedulerJobForUserAndExploratory(anyString(), anyString(), anyString()))
-                .thenReturn(getSchedulerJobDTO());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(getSchedulerJobDTO(), response.readEntity(SchedulerJobDTO.class));
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(schedulerJobService).fetchSchedulerJobForUserAndExploratory(USER.toLowerCase(), "projectName", "explName");
-        verifyNoMoreInteractions(schedulerJobService);
-    }
-
-
-	@Test
-	public void fetchSchedulerJobForUserAndExploratoryWithException() {
-        doThrow(new ResourceNotFoundException("Scheduler job data not found for user with exploratory"))
-                .when(schedulerJobService).fetchSchedulerJobForUserAndExploratory(anyString(), anyString(), anyString());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_NOT_FOUND, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(schedulerJobService).fetchSchedulerJobForUserAndExploratory(USER.toLowerCase(), "projectName", "explName");
-        verifyNoMoreInteractions(schedulerJobService);
-    }
-
-	@Test
-	public void fetchSchedulerJobForComputationalResource() {
-        when(schedulerJobService.fetchSchedulerJobForComputationalResource(anyString(), anyString(), anyString(), anyString()))
-                .thenReturn(getSchedulerJobDTO());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName/compName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(getSchedulerJobDTO(), response.readEntity(SchedulerJobDTO.class));
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(schedulerJobService).fetchSchedulerJobForComputationalResource(USER.toLowerCase(), "projectName",
-                "explName", "compName");
-        verifyNoMoreInteractions(schedulerJobService);
-    }
-
-	@Test
-	public void fetchSchedulerJobForComputationalResourceWithFailedAuth() throws AuthenticationException {
-        authFailSetup();
-        when(schedulerJobService.fetchSchedulerJobForComputationalResource(anyString(), anyString(), anyString(), anyString()))
-                .thenReturn(getSchedulerJobDTO());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName/compName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(getSchedulerJobDTO(), response.readEntity(SchedulerJobDTO.class));
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(schedulerJobService).fetchSchedulerJobForComputationalResource(USER.toLowerCase(), "projectName",
-                "explName", "compName");
-        verifyNoMoreInteractions(schedulerJobService);
-    }
-
-	@Test
-	public void fetchSchedulerJobForComputationalResourceWithException() {
-        doThrow(new ResourceNotFoundException("Scheduler job data not found for user with exploratory with " +
-                "computational resource")).when(schedulerJobService)
-                .fetchSchedulerJobForComputationalResource(anyString(), anyString(), anyString(), anyString());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/scheduler/projectName/explName/compName")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_NOT_FOUND, response.getStatus());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(schedulerJobService).fetchSchedulerJobForComputationalResource(USER.toLowerCase(), "projectName",
-                "explName", "compName");
-        verifyNoMoreInteractions(schedulerJobService);
-    }
-
-	@Test
-	public void testGetActiveSchedulers() {
-		when(schedulerJobService.getActiveSchedulers(anyString(), anyLong()))
-				.thenReturn(Collections.singletonList(new SchedulerJobData(USER, "exploratoryName", null,
-						"project", getSchedulerJobDTO())));
-		final long minuteOffset = 10L;
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment/scheduler/active")
-				.queryParam("minuteOffset", minuteOffset)
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-		final List<SchedulerJobData> activeSchedulers = response.readEntity(new GenericType<List<SchedulerJobData>>() {
-		});
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(1, activeSchedulers.size());
-		assertEquals(Collections.singletonList(new SchedulerJobData(USER, "exploratoryName", null,
-				"project", getSchedulerJobDTO())), activeSchedulers);
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(schedulerJobService).getActiveSchedulers(USER.toLowerCase(), minuteOffset);
-		verifyNoMoreInteractions(schedulerJobService);
-
-	}
-
-	private SchedulerJobDTO getSchedulerJobDTO() {
-		SchedulerJobDTO schedulerJobDTO = new SchedulerJobDTO();
-		schedulerJobDTO.setTimeZoneOffset(OffsetDateTime.now(ZoneId.systemDefault()).getOffset());
-		schedulerJobDTO.setBeginDate(LocalDate.now());
-		schedulerJobDTO.setFinishDate(LocalDate.now().plusDays(1));
-		schedulerJobDTO.setStartTime(LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		schedulerJobDTO.setEndTime(LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		schedulerJobDTO.setTerminateDateTime(
-				LocalDateTime.of(LocalDate.now(), LocalTime.now().truncatedTo(ChronoUnit.MINUTES)));
-		schedulerJobDTO.setStartDaysRepeat(Arrays.asList(DayOfWeek.values()));
-		schedulerJobDTO.setStopDaysRepeat(Arrays.asList(DayOfWeek.values()));
-		schedulerJobDTO.setSyncStartRequired(false);
-		return schedulerJobDTO;
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/SystemInfoResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/SystemInfoResourceTest.java
deleted file mode 100644
index 1d7eea1..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/SystemInfoResourceTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.backendapi.resources.dto.SystemInfoDto;
-import com.epam.dlab.backendapi.service.SystemInfoService;
-import com.epam.dlab.model.systeminfo.DiskInfo;
-import com.epam.dlab.model.systeminfo.MemoryInfo;
-import com.epam.dlab.model.systeminfo.OsInfo;
-import com.epam.dlab.model.systeminfo.ProcessorInfo;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.*;
-
-public class SystemInfoResourceTest extends TestBase {
-
-	private SystemInfoService systemInfoService = mock(SystemInfoService.class);
-
-	@Rule
-	public final ResourceTestRule resources = getResourceTestRuleInstance(new SystemInfoResource(systemInfoService));
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-	@Test
-	public void getSystemInfo() {
-		when(systemInfoService.getSystemInfo()).thenReturn(getSystemInfoDto());
-		final Response response = resources.getJerseyTest()
-				.target("/sysinfo")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(systemInfoService).getSystemInfo();
-		verifyNoMoreInteractions(systemInfoService);
-	}
-
-	@Test
-	public void getSystemInfoWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		when(systemInfoService.getSystemInfo()).thenReturn(getSystemInfoDto());
-		final Response response = resources.getJerseyTest()
-				.target("/sysinfo")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verifyZeroInteractions(systemInfoService);
-	}
-
-	private SystemInfoDto getSystemInfoDto() {
-		OsInfo osInfo = OsInfo.builder()
-				.family(System.getProperty("os.name"))
-				.buildNumber(System.getProperty("os.version"))
-				.build();
-		ProcessorInfo processorInfo = ProcessorInfo.builder().build();
-		MemoryInfo memoryInfo = MemoryInfo.builder().build();
-		DiskInfo diskInfo = DiskInfo.builder().build();
-		return new SystemInfoDto(osInfo, processorInfo, memoryInfo, Collections.singletonList(diskInfo));
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/TestBase.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/TestBase.java
deleted file mode 100644
index 37395a5..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/TestBase.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.rest.mappers.ResourceNotFoundExceptionMapper;
-import io.dropwizard.auth.AuthDynamicFeature;
-import io.dropwizard.auth.AuthValueFactoryProvider;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.auth.Authenticator;
-import io.dropwizard.auth.Authorizer;
-import io.dropwizard.auth.oauth.OAuthCredentialAuthFilter;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.glassfish.jersey.media.multipart.MultiPartFeature;
-import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
-import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
-
-import java.util.Optional;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class TestBase {
-
-	protected final String TOKEN = "TOKEN";
-	protected final String USER = "testUser";
-	protected final String ENDPOINT_NAME = "local";
-	protected final String ENDPOINT_URL = "http://localhost:8443/";
-	protected final String ENDPOINT_ACCOUNT = "account";
-	protected final String ENDPOINT_TAG = "tag";
-
-	@SuppressWarnings("unchecked")
-	private static Authenticator<String, UserInfo> authenticator = mock(Authenticator.class);
-	@SuppressWarnings("unchecked")
-	private static Authorizer<UserInfo> authorizer = mock(Authorizer.class);
-
-	protected <T> ResourceTestRule getResourceTestRuleInstance(T resourceInstance) {
-		return ResourceTestRule.builder()
-				.bootstrapLogging(false)
-				.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
-				.addProvider(new AuthDynamicFeature(new OAuthCredentialAuthFilter.Builder<UserInfo>()
-						.setAuthenticator(authenticator)
-						.setAuthorizer(authorizer)
-						.setRealm("SUPER SECRET STUFF")
-						.setPrefix("Bearer")
-						.buildAuthFilter()))
-				.addProvider(RolesAllowedDynamicFeature.class)
-				.addProvider(new ResourceNotFoundExceptionMapper())
-				.addProvider(new AuthValueFactoryProvider.Binder<>(UserInfo.class))
-				.addProvider(MultiPartFeature.class)
-				.addResource(resourceInstance)
-				.build();
-	}
-
-	protected void authSetup() throws AuthenticationException {
-		when(authenticator.authenticate(TOKEN)).thenReturn(Optional.of(getUserInfo()));
-		when(authorizer.authorize(any(), any())).thenReturn(true);
-	}
-
-	protected void authFailSetup() throws AuthenticationException {
-		when(authenticator.authenticate(TOKEN)).thenReturn(Optional.of(getUserInfo()));
-		when(authorizer.authorize(any(), any())).thenReturn(false);
-	}
-
-	protected UserInfo getUserInfo() {
-		return new UserInfo(USER, TOKEN);
-	}
-
-	protected EndpointDTO getEndpointDTO() {
-		return new EndpointDTO(ENDPOINT_NAME, ENDPOINT_URL, ENDPOINT_ACCOUNT, ENDPOINT_TAG, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/UserGroupResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/UserGroupResourceTest.java
deleted file mode 100644
index 6e32ec0..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/UserGroupResourceTest.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.ProjectDAO;
-import com.epam.dlab.backendapi.resources.dto.GroupDTO;
-import com.epam.dlab.backendapi.resources.dto.UpdateGroupDTO;
-import com.epam.dlab.backendapi.resources.dto.UserGroupDto;
-import com.epam.dlab.backendapi.service.UserGroupService;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class UserGroupResourceTest extends TestBase {
-
-    private static final String USER = "user";
-	private static final String ROLE_ID = "id";
-	private static final String ROLE_DESCRIPTION = "description";
-	private static final String GROUP = "group";
-    private UserGroupService userGroupService = mock(UserGroupService.class);
-    private ProjectDAO projectDAO = mock(ProjectDAO.class);
-
-    @Before
-    public void setup() throws AuthenticationException {
-        authSetup();
-    }
-
-    @Rule
-    public final ResourceTestRule resources =
-            getResourceTestRuleInstance(new UserGroupResource(userGroupService));
-
-	@Test
-	public void createGroup() {
-
-		final Response response = resources.getJerseyTest()
-				.target("/group")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json(getCreateGroupDto(GROUP, Collections.singletonMap(ROLE_ID, ROLE_DESCRIPTION))));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-
-		verify(userGroupService).createGroup(getUserInfo(), GROUP, Collections.singleton(ROLE_ID), Collections.singleton(USER));
-		verifyNoMoreInteractions(userGroupService);
-	}
-
-	@Test
-	public void createGroupWhenGroupNameIsEmpty() {
-
-		final Response response = resources.getJerseyTest()
-				.target("/group")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json(getCreateGroupDto("", Collections.singletonMap(ROLE_ID, ROLE_DESCRIPTION))));
-
-		assertEquals(HttpStatus.SC_UNPROCESSABLE_ENTITY, response.getStatus());
-
-		verifyZeroInteractions(userGroupService);
-	}
-
-	@Test
-	public void createGroupWhenRoleIdIsEmpty() {
-
-		final Response response = resources.getJerseyTest()
-				.target("/group")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json(getCreateGroupDto(GROUP, Collections.emptyMap())));
-
-		assertEquals(HttpStatus.SC_UNPROCESSABLE_ENTITY, response.getStatus());
-
-		verifyZeroInteractions(userGroupService);
-	}
-
-	@Test
-	public void updateGroup() {
-
-		final Response response = resources.getJerseyTest()
-				.target("/group")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.put(Entity.json(getUpdaeGroupDto(GROUP, Collections.singletonMap(ROLE_ID, ROLE_DESCRIPTION), Collections.singleton(USER))));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-
-		verify(userGroupService).updateGroup(getUserInfo(), GROUP, Collections.singletonMap(ROLE_ID, ROLE_DESCRIPTION), Collections.singleton(USER));
-		verifyNoMoreInteractions(userGroupService);
-	}
-
-	@Test
-	public void getGroups() {
-        when(userGroupService.getAggregatedRolesByGroup(any(UserInfo.class))).thenReturn(Collections.singletonList(getUserGroup()));
-
-        final Response response = resources.getJerseyTest()
-                .target("/group")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        final List<UserGroupDto> actualRoles = response.readEntity(new GenericType<List<UserGroupDto>>() {
-        });
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(GROUP, actualRoles.get(0).getGroup());
-        assertTrue(actualRoles.get(0).getRoles().isEmpty());
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(userGroupService).getAggregatedRolesByGroup(getUserInfo());
-        verifyNoMoreInteractions(userGroupService);
-    }
-
-	@Test
-	public void deleteGroup() {
-		final Response response = resources.getJerseyTest()
-				.target("/group/" + GROUP)
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.delete();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-
-
-		verify(userGroupService).removeGroup(getUserInfo(), GROUP);
-		verifyNoMoreInteractions(userGroupService);
-	}
-
-	private UserGroupDto getUserGroup() {
-		return new UserGroupDto(GROUP, Collections.emptyList(), Collections.emptySet());
-	}
-
-	private GroupDTO getCreateGroupDto(String group, Map<String, String> roleIds) {
-		final GroupDTO dto = new GroupDTO();
-		dto.setName(group);
-		dto.setRoleIds(roleIds);
-		dto.setUsers(Collections.singleton(USER));
-		return dto;
-	}
-
-	private UpdateGroupDTO getUpdaeGroupDto(String group, Map<String, String> roles, Set<String> users) {
-		UpdateGroupDTO updateGroupDTO = new UpdateGroupDTO();
-		updateGroupDTO.setName(group);
-		updateGroupDTO.setRoles(roles);
-		updateGroupDTO.setUsers(users);
-		return updateGroupDTO;
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/UserRoleResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/UserRoleResourceTest.java
deleted file mode 100644
index c4e2bd6..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/UserRoleResourceTest.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.backendapi.resources.dto.UserRoleDto;
-import com.epam.dlab.backendapi.service.UserRoleService;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.Collections;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-public class UserRoleResourceTest extends TestBase {
-
-
-	private static final String USER = "user";
-	private static final String ROLE_ID = "id";
-
-	private UserRoleService rolesService = mock(UserRoleService.class);
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-	@Rule
-	public final ResourceTestRule resources =
-			getResourceTestRuleInstance(new UserRoleResource(rolesService));
-
-
-	@Test
-	public void getRoles() {
-		when(rolesService.getUserRoles()).thenReturn(Collections.singletonList(getUserRole()));
-
-		final Response response = resources.getJerseyTest()
-				.target("/role")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		final List<UserRoleDto> actualRoles = response.readEntity(new GenericType<List<UserRoleDto>>() {
-		});
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals(ROLE_ID, actualRoles.get(0).getId());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(rolesService).getUserRoles();
-		verifyNoMoreInteractions(rolesService);
-	}
-
-	@Test
-	public void createRole() {
-
-		final Response response = resources.getJerseyTest()
-				.target("/role")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json(getUserRole()));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-
-		verify(rolesService).createRole(refEq(getUserRole()));
-		verifyNoMoreInteractions(rolesService);
-	}
-
-	private UserRoleDto getUserRole() {
-		final UserRoleDto userRoleDto = new UserRoleDto();
-		userRoleDto.setId(ROLE_ID);
-		return userRoleDto;
-	}
-
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/UserSettingsResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/UserSettingsResourceTest.java
deleted file mode 100644
index be2569c..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/UserSettingsResourceTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * 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.resources;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.resources.dto.UserDTO;
-import com.epam.dlab.backendapi.service.UserSettingService;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.testing.junit.ResourceTestRule;
-import org.apache.http.HttpHeaders;
-import org.apache.http.HttpStatus;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import static java.util.Collections.singletonList;
-import static org.junit.Assert.*;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.refEq;
-import static org.mockito.Mockito.*;
-
-public class UserSettingsResourceTest extends TestBase {
-
-	private UserSettingService userSettingService = mock(UserSettingService.class);
-
-	@Rule
-	public final ResourceTestRule resources =
-			getResourceTestRuleInstance(new UserSettingsResource(userSettingService));
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-	@Test
-	public void getSettings() {
-		when(userSettingService.getUISettings(any(UserInfo.class))).thenReturn("someSettings");
-		final Response response = resources.getJerseyTest()
-				.target("/user/settings")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals("someSettings", response.readEntity(String.class));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(userSettingService).getUISettings(refEq(getUserInfo()));
-		verifyNoMoreInteractions(userSettingService);
-	}
-
-	@Test
-	public void getSettingsWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		when(userSettingService.getUISettings(any(UserInfo.class))).thenReturn("someSettings");
-		final Response response = resources.getJerseyTest()
-				.target("/user/settings")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.get();
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals("someSettings", response.readEntity(String.class));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(userSettingService).getUISettings(refEq(getUserInfo()));
-		verifyNoMoreInteractions(userSettingService);
-	}
-
-	@Test
-	public void saveSettings() {
-		doNothing().when(userSettingService).saveUISettings(any(UserInfo.class), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/user/settings")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json("someSettings"));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(userSettingService).saveUISettings(refEq(getUserInfo()), eq("someSettings"));
-		verifyNoMoreInteractions(userSettingService);
-	}
-
-	@Test
-	public void saveSettingsWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		doNothing().when(userSettingService).saveUISettings(any(UserInfo.class), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/user/settings")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json("someSettings"));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(userSettingService).saveUISettings(refEq(getUserInfo()), eq("someSettings"));
-		verifyNoMoreInteractions(userSettingService);
-	}
-
-	@Test
-	public void saveSettingsWithException() {
-		doThrow(new RuntimeException()).when(userSettingService).saveUISettings(any(UserInfo.class), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/user/settings")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json("someSettings"));
-
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		assertTrue(response.readEntity(String.class).contains("{\"code\":500,\"message\":\"There was an error " +
-				"processing your request. It has been logged"));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(userSettingService).saveUISettings(refEq(getUserInfo()), eq("someSettings"));
-		verifyNoMoreInteractions(userSettingService);
-	}
-
-	@Test
-	public void saveAllowedBudget() {
-		doNothing().when(userSettingService).saveUISettings(any(UserInfo.class), anyString());
-		final Response response = resources.getJerseyTest()
-				.target("/user/settings/budget")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.put(Entity.json(singletonList(new UserDTO(USER, 10, UserDTO.Status.ACTIVE))));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertNull(response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(userSettingService).updateUsersBudget(singletonList(new UserDTO(USER, 10, UserDTO.Status.ACTIVE)));
-		verifyNoMoreInteractions(userSettingService);
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/roles/UserRolesTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/roles/UserRolesTest.java
deleted file mode 100644
index 0fa4c94..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/roles/UserRolesTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.roles;
-
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.SecurityDAO;
-import com.mongodb.client.FindIterable;
-import com.mongodb.client.MongoCursor;
-import org.bson.Document;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class UserRolesTest {
-
-	@Mock
-	private SecurityDAO dao;
-
-	@Test
-	@SuppressWarnings("unchecked")
-	public void checkAccess() {
-		UserInfo userInfoDev = new UserInfo("developer", "token123");
-		userInfoDev.addRole("dev");
-		List<String> shapes1 = new ArrayList<>();
-		shapes1.add("shape_1");
-		shapes1.add("shape_2");
-		shapes1.add("shape_3");
-		ArrayList<String> devGroup = new ArrayList<>();
-		devGroup.add("dev");
-		Document doc1 = new Document().append("exploratory_shapes", shapes1).append("groups", devGroup);
-
-		UserInfo userInfoTest = new UserInfo("tester", "token321");
-		userInfoTest.addRole("test");
-		List<String> shapes2 = new ArrayList<>();
-		shapes2.add("shape_2");
-		shapes2.add("shape_3");
-		ArrayList<String> testGroup = new ArrayList<>();
-		testGroup.add("test");
-		Document doc2 = new Document().append("exploratory_shapes", shapes2).append("groups", testGroup);
-
-		MongoCursor cursor = mock(MongoCursor.class);
-
-		FindIterable mockIterable = mock(FindIterable.class);
-
-		when(dao.getRoles()).thenReturn(mockIterable);
-		when(mockIterable.iterator()).thenReturn(cursor);
-		when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
-		when(cursor.next()).thenReturn(doc1).thenReturn(doc2);
-		UserRoles.initialize(dao, true);
-
-		assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "shape_1", userInfoDev.getRoles()));
-		assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "shape_2", userInfoDev.getRoles()));
-		assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "shape_3", userInfoDev.getRoles()));
-		assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "someShape", userInfoDev.getRoles()));
-
-		assertFalse(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "shape_1", userInfoTest.getRoles()));
-		assertFalse(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "shape_2", userInfoTest.getRoles()));
-		assertFalse(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "shape_3", userInfoTest.getRoles()));
-		assertTrue(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "someShape", userInfoTest.getRoles()));
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/schedulers/CheckApplicationQuoteSchedulerTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/schedulers/CheckApplicationQuoteSchedulerTest.java
deleted file mode 100644
index 99fd932..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/schedulers/CheckApplicationQuoteSchedulerTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.schedulers;
-
-import com.epam.dlab.backendapi.dao.BillingDAO;
-import com.epam.dlab.backendapi.service.EnvironmentService;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.quartz.JobExecutionContext;
-
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class CheckApplicationQuoteSchedulerTest {
-
-	@Mock
-	private BillingDAO billingDAO;
-	@Mock
-	private EnvironmentService environmentService;
-	@Mock
-	private JobExecutionContext jobExecutionContext;
-	@InjectMocks
-	private CheckApplicationQuoteScheduler checkApplicationQuoteScheduler;
-
-	@Test
-	public void testWhenQuoteNotReached() {
-		when(billingDAO.isBillingQuoteReached()).thenReturn(false);
-
-		checkApplicationQuoteScheduler.execute(jobExecutionContext);
-
-		verify(billingDAO).isBillingQuoteReached();
-		verifyNoMoreInteractions(billingDAO);
-		verifyZeroInteractions(environmentService);
-	}
-
-	@Test
-	public void testWhenQuoteReached() {
-		when(billingDAO.isBillingQuoteReached()).thenReturn(true);
-
-		checkApplicationQuoteScheduler.execute(jobExecutionContext);
-
-		verify(billingDAO).isBillingQuoteReached();
-		verify(environmentService).stopAll();
-		verifyNoMoreInteractions(billingDAO, environmentService);
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/schedulers/CheckUserQuoteSchedulerTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/schedulers/CheckUserQuoteSchedulerTest.java
deleted file mode 100644
index 1c6937c..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/schedulers/CheckUserQuoteSchedulerTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.schedulers;
-
-import com.epam.dlab.backendapi.dao.BillingDAO;
-import com.epam.dlab.backendapi.resources.dto.UserDTO;
-import com.epam.dlab.backendapi.service.EnvironmentService;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.quartz.JobExecutionContext;
-
-import java.util.Collections;
-
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class CheckUserQuoteSchedulerTest {
-
-	private static final String USER = "test";
-	@Mock
-	private BillingDAO billingDAO;
-	@Mock
-	private EnvironmentService environmentService;
-	@Mock
-	private JobExecutionContext jobExecutionContext;
-	@InjectMocks
-	private CheckUserQuoteScheduler checkUserQuoteScheduler;
-
-	@Test
-	public void testWhenUserQuoteReached() {
-		when(billingDAO.isUserQuoteReached(anyString())).thenReturn(true);
-		when(environmentService.getUsers()).thenReturn(Collections.singletonList(new UserDTO(USER, 1, UserDTO.Status.ACTIVE)));
-
-		checkUserQuoteScheduler.execute(jobExecutionContext);
-
-		verify(environmentService).getUsers();
-		verify(billingDAO).isUserQuoteReached(USER);
-		verify(environmentService).stopEnvironmentWithServiceAccount(USER);
-		verifyNoMoreInteractions(environmentService, billingDAO);
-		verifyZeroInteractions(jobExecutionContext);
-	}
-
-	@Test
-	public void testWhenUserQuoteNotReached() {
-		when(billingDAO.isUserQuoteReached(anyString())).thenReturn(false);
-		when(environmentService.getUsers()).thenReturn(Collections.singletonList(new UserDTO(USER, 1, UserDTO.Status.ACTIVE)));
-
-		checkUserQuoteScheduler.execute(jobExecutionContext);
-
-		verify(environmentService).getUsers();
-		verify(billingDAO).isUserQuoteReached(USER);
-		verify(environmentService, never()).stopEnvironmentWithServiceAccount(anyString());
-		verifyNoMoreInteractions(environmentService, billingDAO);
-		verifyZeroInteractions(jobExecutionContext);
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/ApplicationSettingServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/ApplicationSettingServiceImplTest.java
deleted file mode 100644
index 317a076..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/ApplicationSettingServiceImplTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.dao.MongoSetting;
-import com.epam.dlab.backendapi.dao.SettingsDAO;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.Collections;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class ApplicationSettingServiceImplTest {
-
-	private static final long MAX_BUDGET = 10L;
-	@Mock
-	private SettingsDAO settingsDAO;
-	@InjectMocks
-	private ApplicationSettingServiceImpl applicationSettingService;
-
-	@Test
-	public void setMaxBudget() {
-
-		applicationSettingService.setMaxBudget(MAX_BUDGET);
-
-		verify(settingsDAO).setMaxBudget(MAX_BUDGET);
-		verifyNoMoreInteractions(settingsDAO);
-	}
-
-	@Test
-	public void getSettings() {
-		when(settingsDAO.getSettings()).thenReturn(Collections.singletonMap("key", "value"));
-		final Map<String, Object> settings = applicationSettingService.getSettings();
-		assertEquals(1, settings.size());
-		assertEquals("value", settings.get("key"));
-
-		verify(settingsDAO).getSettings();
-		verifyNoMoreInteractions(settingsDAO);
-	}
-
-	@Test
-	public void removeMaxBudget() {
-
-		applicationSettingService.removeMaxBudget();
-
-		verify(settingsDAO).removeSetting(MongoSetting.CONF_MAX_BUDGET);
-		verifyNoMoreInteractions(settingsDAO);
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/KeycloakServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/KeycloakServiceImplTest.java
deleted file mode 100644
index d57efa2..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/KeycloakServiceImplTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.SecurityDAO;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.keycloak.representations.AccessTokenResponse;
-import org.mockito.Answers;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.Invocation;
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.Response;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class KeycloakServiceImplTest {
-	private static final String ACCESS_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJNUC15QVpENFdJRzloa" +
-			"np3R0RqQjdCeW9aNGpaV05QTjJ3X25uS1BkTnQ4In0.eyJqdGkiOiJlYTgzZTQ2OS0xNjFhLTQ1ZDUtYWI4YS1mZDUxYThmMzMwMzYiL" +
-			"CJleHAiOjE1NzA0NDQ1NTQsIm5iZiI6MCwiaWF0IjoxNTcwNDQzMzU0LCJpc3MiOiJodHRwOi8vNTIuMTEuNDUuMTE6ODA4MC9hdXRoL" +
-			"3JlYWxtcy9ETEFCX2JobGl2YSIsImF1ZCI6WyJwcm92aXNpb25pbmciLCJhY2NvdW50Il0sInN1YiI6ImRjNzczMThkLWYzN2UtNGNmO" +
-			"S1iMDgwLTU2ZTRjMWUwNDVhNSIsInR5cCI6IkJlYXJlciIsImF6cCI6InNzcyIsImF1dGhfdGltZSI6MTU3MDQ0MzMyOSwic2Vzc2lvb" +
-			"l9zdGF0ZSI6ImVkYTE3ODJjLTliZmItNDQ5Yy1hYWY1LWNhNzM5MDViMmI1NyIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZ" +
-			"XMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7InNzcyI6eyJyb2xlcyI6W" +
-			"yJ0ZXN0Il19LCJwcm92aXNpb25pbmciOnsicm9sZXMiOlsidGVzdCJdfSwiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3Vud" +
-			"CIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSIsImVtY" +
-			"WlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdCJ9.jXjqFP1xmG32NahYnw1spO7fhEyGiqeu0QdBYuo9" +
-			"y6TI8xlAy5EFQ_5SrW6UuzpZUhgCjStH3Qkk_xgLlbZ9IqnxwOmx1i8arlurKf1mY_rm2_C5JBxHdHio8in8yEMls8t-wQOT46kMJNC7" +
-			"4GUzuWWQxS1h6F1V6238rnT8_W27oFcG449ShOGOQ5Du4F9B4ur3Ns6j5oSduwUFlbY_rNpGurUmtFWXBaXM61CiezJPxXu5pHzWK6Xq" +
-			"Z1IkuEUaDDJdBf1OGi13toq88V7C-Pr7YlnyWlbZ7bw2VXAs3NAgtn_30KlgYwR9YUJ_AB5TP3u8kK0jY0vLPosuBZgKeA";
-	private static final String REFRESH_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImUyZjk0YjFmLTBhMjMtNGJi" +
-			"OS05NDUwLTdjNDQ4MTdjY2RkMCJ9.eyJqdGkiOiI0NmNiMzczMy1mM2IzLTRiYjItYmQyZC02N2FjNzg5N2VmNTUiLCJleHAiOjE1NzA" +
-			"0NDMzNTQsIm5iZiI6MCwiaWF0IjoxNTcwNDQzMzU0LCJpc3MiOiJodHRwOi8vNTIuMTEuNDUuMTE6ODA4MC9hdXRoL3JlYWxtcy9ETEF" +
-			"CX2JobGl2YSIsImF1ZCI6Imh0dHA6Ly81Mi4xMS40NS4xMTo4MDgwL2F1dGgvcmVhbG1zL0RMQUJfYmhsaXZhIiwic3ViIjoiZGM3NzM" +
-			"xOGQtZjM3ZS00Y2Y5LWIwODAtNTZlNGMxZTA0NWE1IiwidHlwIjoiUmVmcmVzaCIsImF6cCI6InNzcyIsImF1dGhfdGltZSI6MCwic2V" +
-			"zc2lvbl9zdGF0ZSI6ImVkYTE3ODJjLTliZmItNDQ5Yy1hYWY1LWNhNzM5MDViMmI1NyIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJ" +
-			"vZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsic3NzIjp7InJvbGVzIjpbInRlc3Q" +
-			"iXX0sInByb3Zpc2lvbmluZyI6eyJyb2xlcyI6WyJ0ZXN0Il19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWF" +
-			"uYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIn0.rzkrAprIt0-" +
-			"jD0h9ex3krzfu8UDcgnrRdocNFJmYa30";
-	@Mock
-	private Client httpClient;
-	@Mock
-	private SecurityDAO securityDAO;
-	@Mock(answer = Answers.RETURNS_DEEP_STUBS)
-	private SelfServiceApplicationConfiguration conf;
-
-	private KeycloakServiceImpl keycloakService;
-
-	@Before
-	public void setUp() {
-		keycloakService = new KeycloakServiceImpl(httpClient, conf, securityDAO);
-	}
-
-	@Test
-	public void generateAccessToken() {
-		WebTarget webTarget = mock(WebTarget.class);
-		Invocation.Builder builder = mock(Invocation.Builder.class);
-		Response response = mock(Response.class);
-		Response.StatusType statusType = mock(Response.StatusType.class);
-		AccessTokenResponse tokenResponse = mock(AccessTokenResponse.class);
-
-		when(httpClient.target(anyString())).thenReturn(webTarget);
-		when(webTarget.request()).thenReturn(builder);
-		when(builder.header(any(), anyString())).thenReturn(builder);
-		when(builder.post(any())).thenReturn(response);
-		when(response.getStatusInfo()).thenReturn(statusType);
-		when(response.readEntity(AccessTokenResponse.class)).thenReturn(tokenResponse);
-		when(statusType.getFamily()).thenReturn(Response.Status.Family.SUCCESSFUL);
-		when(tokenResponse.getToken()).thenReturn(ACCESS_TOKEN);
-		doNothing().when(securityDAO).updateUser(anyString(), any(AccessTokenResponse.class));
-
-		keycloakService.generateAccessToken(REFRESH_TOKEN);
-
-		verify(httpClient).target(anyString());
-		verify(securityDAO).updateUser("test", tokenResponse);
-		verifyNoMoreInteractions(securityDAO, httpClient);
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/ProjectServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/ProjectServiceImplTest.java
deleted file mode 100644
index a5c9ebf..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/ProjectServiceImplTest.java
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * 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.auth.UserInfo;
-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;
-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.resources.TestBase;
-import com.epam.dlab.backendapi.service.impl.ProjectServiceImpl;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.project.ProjectActionDTO;
-import com.epam.dlab.dto.project.ProjectCreateDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceConflictException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.rest.client.RESTService;
-import com.google.common.collect.Sets;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyListOf;
-import static org.mockito.Matchers.anySet;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class ProjectServiceImplTest extends TestBase {
-	private static final String CREATE_PRJ_API = "infrastructure/project/create";
-	private static final String TERMINATE_PRJ_API = "infrastructure/project/terminate";
-	private static final String START_PRJ_API = "infrastructure/project/start";
-	private static final String STOP_PRJ_API = "infrastructure/project/stop";
-
-	private static final String NAME1 = "name1";
-	private static final String NAME2 = "name2";
-	private static final String GROUP1 = "group1";
-	private static final String GROUP2 = "group2";
-	private static final String UUID = "uuid";
-
-	private static final List<UserInstanceStatus> notebookStatuses = Arrays.asList(
-			UserInstanceStatus.CREATING, UserInstanceStatus.STARTING, UserInstanceStatus.CREATING_IMAGE,
-			UserInstanceStatus.CONFIGURING, UserInstanceStatus.RECONFIGURING, UserInstanceStatus.STOPPING,
-			UserInstanceStatus.TERMINATING);
-	private static final UserInstanceStatus[] computeStatuses = {UserInstanceStatus.CREATING, UserInstanceStatus.CONFIGURING, UserInstanceStatus.STARTING,
-			UserInstanceStatus.RECONFIGURING, UserInstanceStatus.CREATING_IMAGE, UserInstanceStatus.STOPPING,
-			UserInstanceStatus.TERMINATING};
-
-	@Mock
-	private ProjectDAO projectDAO;
-	@Mock
-	private EndpointService endpointService;
-	@Mock
-	private RESTService provisioningService;
-	@Mock
-	private RequestBuilder requestBuilder;
-	@Mock
-	private RequestId requestId;
-	@Mock
-	private ExploratoryService exploratoryService;
-	@Mock
-	private ExploratoryDAO exploratoryDAO;
-	@Mock
-	private UserGroupDAO userGroupDao;
-	@Mock
-	private SelfServiceApplicationConfiguration configuration;
-	@InjectMocks
-	private ProjectServiceImpl projectService;
-
-	@Test
-	public void getProjects() {
-		List<ProjectDTO> projectsMock = getProjectDTOs();
-		when(projectDAO.getProjects()).thenReturn(projectsMock);
-
-		List<ProjectDTO> projects = projectService.getProjects();
-
-		assertEquals(projects, projectsMock);
-		verify(projectDAO).getProjects();
-		verifyNoMoreInteractions(projectDAO);
-	}
-
-	@Test
-	public void testGetProjects() {
-		List<ProjectDTO> projectsMock = getProjectDTOs();
-		when(projectDAO.getProjects()).thenReturn(projectsMock);
-
-		projectService.getProjects(getUserInfo());
-
-		verify(projectDAO).getProjects();
-		verifyNoMoreInteractions(projectDAO);
-	}
-
-	@Test
-	public void getUserProjects() {
-		List<ProjectDTO> projectsMock = Collections.singletonList(getProjectCreatingDTO());
-		when(projectDAO.getUserProjects(any(UserInfo.class), anyBoolean())).thenReturn(projectsMock);
-
-		List<ProjectDTO> projects = projectService.getUserProjects(getUserInfo(), Boolean.TRUE);
-
-		assertEquals(projectsMock, projects);
-		verify(projectDAO).getUserProjects(getUserInfo(), Boolean.TRUE);
-		verifyNoMoreInteractions(projectDAO);
-	}
-
-	@Test
-	public void getProjectsByEndpoint() {
-		List<ProjectDTO> projectsMock = Collections.singletonList(getProjectCreatingDTO());
-		when(projectDAO.getProjectsByEndpoint(anyString())).thenReturn(projectsMock);
-
-		List<ProjectDTO> projects = projectService.getProjectsByEndpoint(ENDPOINT_NAME);
-
-		assertEquals(projectsMock, projects);
-		verify(projectDAO).getProjectsByEndpoint(ENDPOINT_NAME);
-		verifyNoMoreInteractions(projectDAO);
-	}
-
-	@Test
-	public void create() {
-		when(projectDAO.get(anyString())).thenReturn(Optional.empty());
-		when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
-		when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
-		when(requestBuilder.newProjectCreate(any(UserInfo.class), any(ProjectDTO.class), any(EndpointDTO.class))).thenReturn(newProjectCreate());
-
-		ProjectDTO projectDTO = getProjectCreatingDTO();
-		projectService.create(getUserInfo(), projectDTO, projectDTO.getName());
-
-		verify(projectDAO).get(NAME1);
-		verify(projectDAO).create(projectDTO);
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(requestBuilder).newProjectCreate(getUserInfo(), projectDTO, getEndpointDTO());
-		verify(provisioningService).post(ENDPOINT_URL + CREATE_PRJ_API, TOKEN, newProjectCreate(), String.class);
-		verify(requestId).put(USER.toLowerCase(), UUID);
-		verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder);
-	}
-
-	@Test(expected = ResourceConflictException.class)
-	public void createWithException() {
-		when(projectDAO.get(anyString())).thenReturn(Optional.of(getProjectCreatingDTO()));
-
-		ProjectDTO projectDTO = getProjectCreatingDTO();
-		projectService.create(getUserInfo(), projectDTO, projectDTO.getName());
-
-		verify(projectDAO).get(NAME1);
-		verifyNoMoreInteractions(projectDAO);
-	}
-
-	@Test
-	public void get() {
-		ProjectDTO projectMock = getProjectCreatingDTO();
-		when(projectDAO.get(anyString())).thenReturn(Optional.of(projectMock));
-
-		ProjectDTO project = projectService.get(NAME1);
-
-		assertEquals(projectMock, project);
-		verify(projectDAO).get(NAME1);
-		verifyNoMoreInteractions(projectDAO);
-	}
-
-	@Test(expected = ResourceNotFoundException.class)
-	public void getWithException() {
-		when(projectDAO.get(anyString())).thenReturn(Optional.empty());
-
-		projectService.get(NAME1);
-
-		verify(projectDAO).get(NAME1);
-		verifyNoMoreInteractions(projectDAO);
-	}
-
-	@Test
-	public void terminateEndpoint() {
-		when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
-		when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
-		when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
-
-		projectService.terminateEndpoint(getUserInfo(), ENDPOINT_NAME, NAME1);
-
-		verify(exploratoryService).updateProjectExploratoryStatuses(getUserInfo(), NAME1, ENDPOINT_NAME, UserInstanceStatus.TERMINATING);
-		verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.TERMINATING);
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).post(ENDPOINT_URL + TERMINATE_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
-		verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
-		verify(requestId).put(USER.toLowerCase(), UUID);
-		verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, exploratoryService);
-	}
-
-	@Test
-	public void terminateEndpointWithException() {
-		when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
-		when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
-		when(provisioningService.post(anyString(), anyString(), any(), any())).thenThrow(new DlabException("Exception message"));
-
-		projectService.terminateEndpoint(getUserInfo(), ENDPOINT_NAME, NAME1);
-
-		verify(exploratoryService).updateProjectExploratoryStatuses(getUserInfo(), NAME1, ENDPOINT_NAME, UserInstanceStatus.TERMINATING);
-		verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.TERMINATING);
-		verify(projectDAO).updateStatus(NAME1, ProjectDTO.Status.FAILED);
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).post(ENDPOINT_URL + TERMINATE_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
-		verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
-		verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, exploratoryService);
-	}
-
-	@Test
-	public void testTerminateEndpoint() {
-		when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
-		when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
-		when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
-		when(projectDAO.get(anyString())).thenReturn(Optional.of(getProjectRunningDTO()));
-		when(exploratoryDAO.fetchProjectEndpointExploratoriesWhereStatusIn(anyString(), anyListOf(String.class), anyListOf(UserInstanceStatus.class)))
-				.thenReturn(Collections.emptyList());
-
-		projectService.terminateEndpoint(getUserInfo(), Collections.singletonList(ENDPOINT_NAME), NAME1);
-
-		verify(projectDAO).get(NAME1);
-		verify(exploratoryDAO).fetchProjectEndpointExploratoriesWhereStatusIn(NAME1, Collections.singletonList(ENDPOINT_NAME), notebookStatuses, computeStatuses);
-		verify(exploratoryService).updateProjectExploratoryStatuses(getUserInfo(), NAME1, ENDPOINT_NAME, UserInstanceStatus.TERMINATING);
-		verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.TERMINATING);
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).post(ENDPOINT_URL + TERMINATE_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
-		verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
-		verify(requestId).put(USER.toLowerCase(), UUID);
-		verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, exploratoryDAO);
-	}
-
-	@Test(expected = ResourceConflictException.class)
-	public void testTerminateEndpointWithException1() {
-		when(projectDAO.get(anyString())).thenReturn(Optional.of(getProjectCreatingDTO()));
-
-		projectService.terminateEndpoint(getUserInfo(), Collections.singletonList(ENDPOINT_NAME), NAME1);
-
-		verify(projectDAO).get(NAME1);
-		verifyNoMoreInteractions(projectDAO);
-	}
-
-	@Test
-	public void start() {
-		when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
-		when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
-		when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
-
-		projectService.start(getUserInfo(), ENDPOINT_NAME, NAME1);
-
-		verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.STARTING);
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).post(ENDPOINT_URL + START_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
-		verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
-		verify(requestId).put(USER.toLowerCase(), UUID);
-		verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, requestId);
-	}
-
-	@Test
-	public void testStart() {
-		when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
-		when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
-		when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
-
-		projectService.start(getUserInfo(), Collections.singletonList(ENDPOINT_NAME), NAME1);
-
-		verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.STARTING);
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).post(ENDPOINT_URL + START_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
-		verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
-		verify(requestId).put(USER.toLowerCase(), UUID);
-		verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, requestId);
-	}
-
-	@Test
-	public void stop() {
-		when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
-		when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
-		when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
-
-		projectService.stop(getUserInfo(), ENDPOINT_NAME, NAME1, null);
-
-		verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.STOPPING);
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).post(ENDPOINT_URL + STOP_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
-		verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
-		verify(requestId).put(USER.toLowerCase(), UUID);
-		verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, requestId);
-	}
-
-	@Test
-	public void stopWithResources() {
-		when(endpointService.get(anyString())).thenReturn(getEndpointDTO());
-		when(provisioningService.post(anyString(), anyString(), any(), any())).thenReturn(UUID);
-		when(requestBuilder.newProjectAction(any(UserInfo.class), anyString(), any(EndpointDTO.class))).thenReturn(getProjectActionDTO());
-		when(projectDAO.get(anyString())).thenReturn(Optional.of(getProjectRunningDTO()));
-		when(exploratoryDAO.fetchProjectEndpointExploratoriesWhereStatusIn(anyString(), anyListOf(String.class), anyListOf(UserInstanceStatus.class)))
-				.thenReturn(Collections.emptyList());
-
-		projectService.stopWithResources(getUserInfo(), Collections.singletonList(ENDPOINT_NAME), NAME1);
-
-		verify(projectDAO).get(NAME1);
-		verify(exploratoryDAO).fetchProjectEndpointExploratoriesWhereStatusIn(NAME1, Collections.singletonList(ENDPOINT_NAME), notebookStatuses, computeStatuses);
-		verify(projectDAO).updateEdgeStatus(NAME1, ENDPOINT_NAME, UserInstanceStatus.STOPPING);
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).post(ENDPOINT_URL + STOP_PRJ_API, TOKEN, getProjectActionDTO(), String.class);
-		verify(requestBuilder).newProjectAction(getUserInfo(), NAME1, getEndpointDTO());
-		verify(requestId).put(USER.toLowerCase(), UUID);
-		verifyNoMoreInteractions(projectDAO, endpointService, provisioningService, requestBuilder, requestId);
-	}
-
-	@Test
-	public void update() {
-	}
-
-	@Test
-	public void updateBudget() {
-		projectService.updateBudget(getUserInfo(), Collections.singletonList(getUpdateProjectBudgetDTO()));
-
-		verify(projectDAO).updateBudget(NAME1, 10, true);
-		verifyNoMoreInteractions(projectDAO);
-	}
-
-	@Test
-	public void isAnyProjectAssigned() {
-		when(userGroupDao.getUserGroups(anyString())).thenReturn(Sets.newHashSet(GROUP1));
-		when(projectDAO.isAnyProjectAssigned(anySet())).thenReturn(Boolean.TRUE);
-
-		final boolean anyProjectAssigned = projectService.isAnyProjectAssigned(getUserInfo());
-
-		assertEquals(anyProjectAssigned, Boolean.TRUE);
-		verify(userGroupDao).getUserGroups(USER.toLowerCase());
-		verify(projectDAO).isAnyProjectAssigned(Sets.newHashSet(GROUP1));
-		verifyNoMoreInteractions(userGroupDao, projectDAO);
-	}
-
-	@Test
-	public void checkExploratoriesAndComputationalProgress() {
-		when(exploratoryDAO.fetchProjectEndpointExploratoriesWhereStatusIn(anyString(), anyListOf(String.class), anyListOf(UserInstanceStatus.class)))
-				.thenReturn(Collections.emptyList());
-
-		final boolean b = projectService.checkExploratoriesAndComputationalProgress(NAME1, Collections.singletonList(ENDPOINT_NAME));
-
-		assertEquals(b, Boolean.TRUE);
-		verify(exploratoryDAO).fetchProjectEndpointExploratoriesWhereStatusIn(NAME1, Collections.singletonList(ENDPOINT_NAME), notebookStatuses, computeStatuses);
-		verifyNoMoreInteractions(exploratoryDAO);
-	}
-
-	private List<ProjectDTO> getProjectDTOs() {
-		ProjectDTO project1 = ProjectDTO.builder()
-				.name(NAME1)
-				.groups(getGroup(GROUP1))
-				.build();
-		ProjectDTO project2 = ProjectDTO.builder()
-				.name(NAME2)
-				.groups(getGroup(GROUP2))
-				.build();
-		return Arrays.asList(project1, project2);
-	}
-
-	private ProjectDTO getProjectCreatingDTO() {
-		ProjectEndpointDTO projectEndpointDTO = new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.CREATING, null);
-		return ProjectDTO.builder()
-				.name(NAME1)
-				.groups(getGroup(GROUP1))
-				.endpoints(Collections.singletonList(projectEndpointDTO))
-				.build();
-	}
-
-	private ProjectDTO getProjectRunningDTO() {
-		ProjectEndpointDTO projectEndpointDTO = new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, null);
-		return ProjectDTO.builder()
-				.name(NAME1)
-				.groups(getGroup(GROUP1))
-				.endpoints(Collections.singletonList(projectEndpointDTO))
-				.build();
-	}
-
-	private Set<String> getGroup(String group) {
-		return Collections.singleton(group);
-	}
-
-	private ProjectCreateDTO newProjectCreate() {
-		return ProjectCreateDTO.builder()
-				.name(NAME1)
-				.endpoint(ENDPOINT_NAME)
-				.build();
-	}
-
-	private ProjectActionDTO getProjectActionDTO() {
-		return new ProjectActionDTO(NAME1, ENDPOINT_NAME);
-	}
-
-	private UpdateProjectBudgetDTO getUpdateProjectBudgetDTO() {
-		return new UpdateProjectBudgetDTO(NAME1, 10, true);
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/SecurityServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/SecurityServiceImplTest.java
deleted file mode 100644
index 85b78db..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/SecurityServiceImplTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.SecurityDAO;
-import com.epam.dlab.backendapi.domain.AuditActionEnum;
-import com.epam.dlab.backendapi.domain.AuditDTO;
-import com.epam.dlab.exceptions.DlabException;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.keycloak.representations.AccessTokenResponse;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.Optional;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class SecurityServiceImplTest {
-
-	private static final String CODE = "code";
-	private static final String TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJNUC15QVpENFdJRzloanp3R0RqQjdCeW9aNGpaV05QTjJ3X25uS1BkTnQ4In0.eyJqdGkiOiJkN2U0MDk3Yi1hNjdlLTQxYWUtYjBiNC05MzE1YWFmOGZkMDciLCJleHAiOjE1OTkwNDI1ODgsIm5iZiI6MCwiaWF0IjoxNTk5MDM4OTg4LCJpc3MiOiJodHRwOi8vNTIuMTEuNDUuMTE6ODA4MC9hdXRoL3JlYWxtcy9ETEFCX2JobGl2YSIsImF1ZCI6WyJwcm92aXNpb25pbmciLCJhY2NvdW50Il0sInN1YiI6ImRjNzczMThkLWYzN2UtNGNmOS1iMDgwLTU2ZTRjMWUwNDVhNSIsInR5cCI6IkJlYXJlciIsImF6cCI6InNzcyIsImF1dGhfdGltZSI6MTU5OTAzODk4Nywic2Vzc2lvbl9zdGF0ZSI6Ijg2Njg3NzQ3LTNlOGUtNDhhYy1iMTE1LWM4ZDRmNzQ5M2M1ZSIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7InNzcyI6eyJyb2xlcyI6WyJ0ZXN0Il19LCJwcm92aXNpb25pbmciOnsicm9sZXMiOlsidGVzdCJdfSwiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdCIsImVtYWlsIjoidGVzdEBlcGFtLmNvbSJ9.cYXGXjHGOg2XKADNGuQSykb6aUc-_CC4cUaTJ9qVml0IZDPYcUF9H_iTB-vL67k5MpuM4mVpZWHYT9oJYuFKZoR5lPUmiHG3A8LWxZq4ALeTEqWzOdOn2hUsoPSVoaTG8nLqgOQFHAV8G66dD-0zy-8QheGwZznXZ2_lRvSIg-IYRj_vhv91AItNQQ2eXho7zAic_QiLQHo5vUIEOGcVQdRkiVXe-CZ9pe8lHw8tlKwLlHJj7ldv1YVi0m8f9Tztn2ylSoETwSXdmk09pLxzoFG1EP-EU5cDE5l_MDJIVdhGFJR8eLd8dyzFjThupSMwgWEr_iDmbZ4Q116sv8g4jw";
-	private static final String REFRESH_TOKEN = "refreshToken";
-	private static final String USERNAME = "test";
-
-	@Mock
-	private KeycloakService keycloakService;
-	@Mock
-	private SecurityDAO securityDAO;
-	@Mock
-	private AuditService auditService;
-
-	@InjectMocks
-	private SecurityServiceImpl securityService;
-
-	@Test
-	public void testGetUserInfo() {
-		AccessTokenResponse tokenResponse = mock(AccessTokenResponse.class);
-		when(tokenResponse.getToken()).thenReturn(TOKEN);
-		when(tokenResponse.getRefreshToken()).thenReturn(REFRESH_TOKEN);
-		when(keycloakService.getToken(anyString())).thenReturn(tokenResponse);
-
-		UserInfo actualUserInfo = securityService.getUserInfo(CODE);
-
-		assertEquals("UserInfo should be equal", getUserInfoWithRefreshToken(), actualUserInfo);
-		verify(keycloakService).getToken(CODE);
-		verify(securityDAO).saveUser(USERNAME, tokenResponse);
-		verify(auditService).save(getAuditDTO());
-		verifyNoMoreInteractions(keycloakService, securityDAO, auditService);
-	}
-
-	@Test
-	public void getUserInfoOffline() {
-		AccessTokenResponse tokenResponseFromDB = mock(AccessTokenResponse.class);
-		when(tokenResponseFromDB.getRefreshToken()).thenReturn(REFRESH_TOKEN);
-		when(securityDAO.getTokenResponse(anyString())).thenReturn(Optional.of(tokenResponseFromDB));
-		AccessTokenResponse tokenResponse = mock(AccessTokenResponse.class);
-		when(tokenResponse.getToken()).thenReturn(TOKEN);
-		when(keycloakService.refreshToken(anyString())).thenReturn(tokenResponse);
-
-		UserInfo actualUserInfoOffline = securityService.getUserInfoOffline(USERNAME);
-
-		assertEquals("UserInfo should be equal", getUserInfo(), actualUserInfoOffline);
-		verify(securityDAO).getTokenResponse(USERNAME);
-		verify(keycloakService).refreshToken(REFRESH_TOKEN);
-		verifyNoMoreInteractions(securityDAO, keycloakService);
-	}
-
-	@Test(expected = DlabException.class)
-	public void getUserInfoOfflineWithException() {
-		when(securityDAO.getTokenResponse(anyString())).thenReturn(Optional.empty());
-
-		securityService.getUserInfoOffline(USERNAME);
-
-		verify(securityDAO).getTokenResponse(USERNAME);
-		verifyNoMoreInteractions(securityDAO, keycloakService);
-	}
-
-	@Test
-	public void getServiceAccountInfo() {
-		AccessTokenResponse tokenResponse = mock(AccessTokenResponse.class);
-		when(tokenResponse.getToken()).thenReturn(TOKEN);
-		when(keycloakService.generateServiceAccountToken()).thenReturn(tokenResponse);
-
-		UserInfo actualUserInfo = securityService.getServiceAccountInfo(USERNAME);
-
-		assertEquals("UserInfo should be equal", getUserInfo(), actualUserInfo);
-		verify(keycloakService).generateServiceAccountToken();
-		verifyNoMoreInteractions(keycloakService);
-	}
-
-
-	private UserInfo getUserInfo() {
-		return new UserInfo(USERNAME, TOKEN);
-	}
-
-	private UserInfo getUserInfoWithRefreshToken() {
-		UserInfo userInfo = new UserInfo(USERNAME, TOKEN);
-		userInfo.setRefreshToken(REFRESH_TOKEN);
-		return userInfo;
-	}
-
-	private AuditDTO getAuditDTO() {
-		return AuditDTO.builder()
-				.user(USERNAME)
-				.action(AuditActionEnum.LOG_IN)
-				.build();
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/TagServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/TagServiceImplTest.java
deleted file mode 100644
index ea6739c..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/TagServiceImplTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.resources.TestBase;
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-
-public class TagServiceImplTest extends TestBase {
-
-	private static final String PROJECT = "project";
-	private static final String ENDPOINT = "endpoint";
-	private static final String CUSTOM_TAG = "customTag";
-
-	TagService tagService = new TagServiceImpl();
-
-	@Test
-	public void getResourceTags() {
-		Map<String, String> actualResourceTags = tagService.getResourceTags(getUserInfo(), ENDPOINT, PROJECT, CUSTOM_TAG);
-
-		assertEquals("maps of tags are not equals", getExpectedResourceTags(), actualResourceTags);
-	}
-
-	@Test
-	public void getResourceTagsWithNullCustomTag() {
-		Map<String, String> actualResourceTags = tagService.getResourceTags(getUserInfo(), ENDPOINT, PROJECT, null);
-
-		assertEquals("maps of tags are not equals", getExpectedResourceTagsWithNullCustomTag(), actualResourceTags);
-	}
-
-	private Map<String, String> getExpectedResourceTags() {
-		Map<String, String> resourceTags = new HashMap<>();
-		resourceTags.put("user_tag", USER.toLowerCase());
-		resourceTags.put("endpoint_tag", ENDPOINT);
-		resourceTags.put("project_tag", PROJECT);
-		resourceTags.put("custom_tag", CUSTOM_TAG);
-
-		return resourceTags;
-	}
-
-	private Map<String, String> getExpectedResourceTagsWithNullCustomTag() {
-		Map<String, String> resourceTags = new HashMap<>();
-		resourceTags.put("user_tag", USER.toLowerCase());
-		resourceTags.put("endpoint_tag", ENDPOINT);
-		resourceTags.put("project_tag", PROJECT);
-
-		return resourceTags;
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/UserRoleServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/UserRoleServiceImplTest.java
deleted file mode 100644
index ef7ac34..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/UserRoleServiceImplTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.dao.UserRoleDAO;
-import com.epam.dlab.backendapi.resources.TestBase;
-import com.epam.dlab.backendapi.resources.dto.UserRoleDto;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class UserRoleServiceImplTest extends TestBase {
-
-	private static final String ROLE_ID = "roleId";
-	@Mock
-	private UserRoleDAO dao;
-	@InjectMocks
-	private UserRoleServiceImpl userRoleService;
-	@Rule
-	public ExpectedException expectedException = ExpectedException.none();
-
-	@Test
-	public void createRole() {
-
-		userRoleService.createRole(getUserRole());
-
-		verify(dao).insert(refEq(getUserRole()));
-		verifyNoMoreInteractions(dao);
-	}
-
-	@Test
-	public void updateRole() {
-		when(dao.update(any())).thenReturn(true);
-		userRoleService.updateRole(getUserRole());
-
-		verify(dao).update(refEq(getUserRole()));
-		verifyNoMoreInteractions(dao);
-	}
-
-	@Test
-	public void updateRoleWithException() {
-
-		expectedException.expectMessage("Any of role : [" + ROLE_ID + "] were not found");
-		expectedException.expect(ResourceNotFoundException.class);
-		when(dao.update(any())).thenReturn(false);
-		userRoleService.updateRole(getUserRole());
-	}
-
-	@Test
-	public void removeRole() {
-
-		userRoleService.removeRole(ROLE_ID);
-
-		verify(dao).remove(ROLE_ID);
-		verifyNoMoreInteractions(dao);
-	}
-
-	private UserRoleDto getUserRole() {
-		final UserRoleDto userRoleDto = new UserRoleDto();
-		userRoleDto.setId(ROLE_ID);
-		return userRoleDto;
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/UserSettingServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/UserSettingServiceImplTest.java
deleted file mode 100644
index e44d8eb..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/UserSettingServiceImplTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.UserSettingsDAO;
-import com.epam.dlab.backendapi.resources.dto.UserDTO;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.refEq;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class UserSettingServiceImplTest {
-
-	private static final String SETTINGS = "settings";
-	private static final String TOKEN = "Token";
-	private static final String USER = "user";
-	private static final Integer BUDGET = 10;
-	@Mock
-	private UserSettingsDAO settingsDAO;
-	@InjectMocks
-	private UserSettingServiceImpl userSettingService;
-
-	@Test
-	public void saveUISettings() {
-		userSettingService.saveUISettings(getUserInfo(), SETTINGS);
-
-		verify(settingsDAO).setUISettings(refEq(getUserInfo()), eq(SETTINGS));
-		verifyNoMoreInteractions(settingsDAO);
-	}
-
-	@Test
-	public void getUISettings() {
-		when(settingsDAO.getUISettings(any(UserInfo.class))).thenReturn(SETTINGS);
-
-		final String uiSettings = userSettingService.getUISettings(getUserInfo());
-
-		assertEquals(SETTINGS, uiSettings);
-		verify(settingsDAO).getUISettings(refEq(getUserInfo()));
-	}
-
-	@Test
-	public void updateUsersBudget() {
-
-		userSettingService.updateUsersBudget(Collections.singletonList(getBudgetDTO()));
-
-		verify(settingsDAO).updateBudget(refEq(getBudgetDTO()));
-		verifyNoMoreInteractions(settingsDAO);
-	}
-
-	private UserDTO getBudgetDTO() {
-		return new UserDTO(USER, BUDGET, UserDTO.Status.ACTIVE);
-	}
-
-
-	private UserInfo getUserInfo() {
-		return new UserInfo(USER, TOKEN);
-	}
-
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/AccessKeyServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/AccessKeyServiceImplTest.java
deleted file mode 100644
index f064c42..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/AccessKeyServiceImplTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.resources.TestBase;
-import com.epam.dlab.backendapi.resources.dto.KeysDTO;
-import com.epam.dlab.exceptions.DlabException;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class AccessKeyServiceImplTest extends TestBase {
-
-	@Mock
-	private SelfServiceApplicationConfiguration conf;
-
-	@InjectMocks
-	private AccessKeyServiceImpl accessKeyService;
-
-
-	@Test
-	public void generateKeys() {
-		UserInfo userInfo = getUserInfo();
-		when(conf.getPrivateKeySize()).thenReturn(2048);
-
-		KeysDTO keysDTO = accessKeyService.generateKeys(userInfo);
-
-		assertEquals("Usernames are not equal", USER.toLowerCase(), keysDTO.getUsername());
-		assertNotNull("Public key is null", keysDTO.getPublicKey());
-		assertNotNull("Private key is null", keysDTO.getPrivateKey());
-	}
-
-	@Test(expected = DlabException.class)
-	public void generateKeysWithException() {
-		UserInfo userInfo = getUserInfo();
-		when(conf.getPrivateKeySize()).thenReturn(0);
-
-		accessKeyService.generateKeys(userInfo);
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/AuditServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/AuditServiceImplTest.java
deleted file mode 100644
index da0c002..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/AuditServiceImplTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.AuditActionEnum;
-import com.epam.dlab.backendapi.domain.AuditCreateDTO;
-import com.epam.dlab.backendapi.domain.AuditDTO;
-import com.epam.dlab.backendapi.domain.AuditResourceTypeEnum;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.refEq;
-import static org.mockito.Mockito.verify;
-
-@RunWith(MockitoJUnitRunner.class)
-public class AuditServiceImplTest {
-	private static final String USER = "user";
-	private static final String PROJECT = "project";
-	private static final String RESOURCE_NAME = "resourceName";
-	private static final String INFO = "info";
-
-	@Mock
-	private AuditDAO auditDAO;
-	@InjectMocks
-	private AuditServiceImpl auditService;
-
-	@Test
-	public void save() {
-		AuditDTO auditDTO = getAuditDTO();
-
-		auditService.save(auditDTO);
-
-		verify(auditDAO).save(refEq(auditDTO));
-	}
-
-	@Test
-	public void testSave() {
-		AuditCreateDTO auditCreateDTO = getAuditCreateDTO();
-
-		auditService.save(USER, auditCreateDTO);
-
-		verify(auditDAO).save(eq(getAuditDTO(USER, auditCreateDTO)));
-	}
-
-	@Test
-	public void getAudit() {
-		List<String> users = new ArrayList<>();
-		List<String> projects = new ArrayList<>();
-		List<String> resourceNames = new ArrayList<>();
-		List<String> resourceTypes = new ArrayList<>();
-		String dateStart = "";
-		String dateEnd = "";
-		int pageNumber = 1;
-		int pageSize = 10;
-
-		auditService.getAudit(users, projects, resourceNames, resourceTypes, dateStart, dateEnd, pageNumber, pageSize);
-
-		verify(auditDAO).getAudit(refEq(users), refEq(projects), refEq(resourceNames), refEq(resourceTypes), eq(dateStart), eq(dateEnd), eq(pageNumber), eq(pageSize));
-	}
-
-	private AuditDTO getAuditDTO() {
-		return AuditDTO.builder()
-				.user(USER)
-				.project(PROJECT)
-				.build();
-	}
-
-	private AuditDTO getAuditDTO(String user, AuditCreateDTO auditCreateDTO) {
-		return AuditDTO.builder()
-				.user(user)
-				.resourceName(auditCreateDTO.getResourceName())
-				.info(auditCreateDTO.getInfo())
-				.type(auditCreateDTO.getType())
-				.action(AuditActionEnum.FOLLOW_LINK)
-				.build();
-	}
-
-	private AuditCreateDTO getAuditCreateDTO() {
-		return new AuditCreateDTO(RESOURCE_NAME, INFO, AuditResourceTypeEnum.COMPUTE);
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/BackupServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/BackupServiceImplTest.java
deleted file mode 100644
index e8916e8..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/BackupServiceImplTest.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.BackupDAO;
-import com.epam.dlab.backendapi.resources.dto.BackupInfoRecord;
-import com.epam.dlab.dto.backup.EnvBackupDTO;
-import com.epam.dlab.dto.backup.EnvBackupStatus;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.BackupAPI;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class BackupServiceImplTest {
-
-	private final String USER = "test";
-
-	@Mock
-	private RESTService provisioningService;
-	@Mock
-	private BackupDAO backupDao;
-
-	@InjectMocks
-	private BackupServiceImpl backupService;
-
-	@Rule
-	public ExpectedException expectedException = ExpectedException.none();
-
-
-	@Test
-	public void createBackup() {
-		doNothing().when(backupDao).createOrUpdate(any(EnvBackupDTO.class), anyString(), any(EnvBackupStatus.class));
-		String expectedUuid = "1234-56789765-4321";
-		String token = "token";
-		when(provisioningService.post(refEq(BackupAPI.BACKUP), eq(token), any(EnvBackupDTO.class), any()))
-				.thenReturn(expectedUuid);
-
-		EnvBackupDTO ebDto = EnvBackupDTO.builder().build();
-		UserInfo userInfo = new UserInfo(USER, token);
-		String uuid = backupService.createBackup(ebDto, userInfo);
-		assertNotNull(uuid);
-		assertEquals(expectedUuid, uuid);
-
-		verify(backupDao).createOrUpdate(ebDto, USER, EnvBackupStatus.CREATING);
-		verify(provisioningService).post(BackupAPI.BACKUP, token, ebDto, String.class);
-		verifyNoMoreInteractions(backupDao, provisioningService);
-	}
-
-	@Test
-	public void updateStatus() {
-		doNothing().when(backupDao).createOrUpdate(any(EnvBackupDTO.class), anyString(), any(EnvBackupStatus.class));
-
-		EnvBackupDTO ebDto = EnvBackupDTO.builder().build();
-		backupService.updateStatus(ebDto, USER, EnvBackupStatus.CREATING);
-
-		verify(backupDao).createOrUpdate(ebDto, USER, EnvBackupStatus.CREATING);
-		verifyNoMoreInteractions(backupDao);
-	}
-
-	@Test
-	public void getBackups() {
-		BackupInfoRecord biRecord = mock(BackupInfoRecord.class);
-		when(backupDao.getBackups(anyString())).thenReturn(Collections.singletonList(biRecord));
-
-		List<BackupInfoRecord> biRecords = backupService.getBackups(USER);
-		assertNotNull(biRecords);
-		assertEquals(1, biRecords.size());
-		assertEquals(Collections.singletonList(biRecord), biRecords);
-
-		verify(backupDao).getBackups(USER);
-		verifyNoMoreInteractions(backupDao);
-	}
-
-	@Test
-	public void getBackup() {
-		BackupInfoRecord biRecord = mock(BackupInfoRecord.class);
-		when(backupDao.getBackup(anyString(), anyString())).thenReturn(Optional.of(biRecord));
-
-		String id = "someId";
-		BackupInfoRecord actualBiRecord = backupService.getBackup(USER, id);
-		assertNotNull(actualBiRecord);
-		assertEquals(biRecord, actualBiRecord);
-
-		verify(backupDao).getBackup(USER, id);
-		verifyNoMoreInteractions(backupDao);
-	}
-
-	@Test
-	public void getBackupWithException() {
-		String id = "someId";
-		doThrow(new ResourceNotFoundException(String.format("Backup with id %s was not found for user %s", id, USER)))
-				.when(backupDao).getBackup(USER, id);
-		expectedException.expect(ResourceNotFoundException.class);
-		expectedException.expectMessage("Backup with id " + id + " was not found for user " + USER);
-
-		backupService.getBackup(USER, id);
-	}
-
-	@Test
-	public void getBackupWhenBackupIsAbsent() {
-		String id = "someId";
-		when(backupDao.getBackup(USER, id)).thenReturn(Optional.empty());
-		expectedException.expect(ResourceNotFoundException.class);
-		expectedException.expectMessage("Backup with id " + id + " was not found for user " + USER);
-
-		backupService.getBackup(USER, id);
-	}
-
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/BillingServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/BillingServiceImplTest.java
deleted file mode 100644
index 43439cf..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/BillingServiceImplTest.java
+++ /dev/null
@@ -1,739 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.BillingDAO;
-import com.epam.dlab.backendapi.dao.ImageExploratoryDAO;
-import com.epam.dlab.backendapi.dao.ProjectDAO;
-import com.epam.dlab.backendapi.domain.BillingReport;
-import com.epam.dlab.backendapi.domain.BillingReportLine;
-import com.epam.dlab.backendapi.domain.BudgetDTO;
-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.resources.TestBase;
-import com.epam.dlab.backendapi.resources.dto.BillingFilter;
-import com.epam.dlab.backendapi.resources.dto.ImageInfoRecord;
-import com.epam.dlab.backendapi.resources.dto.QuotaUsageDTO;
-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.cloud.CloudProvider;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.billing.BillingData;
-import com.epam.dlab.dto.billing.BillingResourceType;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.dto.exploratory.ImageStatus;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import javax.ws.rs.core.GenericType;
-import java.time.LocalDate;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.StringJoiner;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyListOf;
-import static org.mockito.Matchers.anySet;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class BillingServiceImplTest extends TestBase {
-
-	private static final String PROJECT = "project";
-	private static final String PROJECT_2 = "project2";
-	private static final String ENDPOINT = "endpoint";
-	private static final String USAGE_DATE = "2020-06-00";
-	private static final String USAGE_DATE_FORMATTED = "2020-06";
-	private static final String SERVICE_BASE_NAME = "sbn";
-	private static final String IMAGE_NAME = "image_name";
-	private static final String IMAGE_DESCRIPTION = "imageDescription";
-	private static final String IMAGE_APPLICATION = "image_application";
-	private static final String IMAGE_FULL_NAME = "imageFullName";
-	private static final String BILLING_URL = "http://localhost:8088/api/billing";
-	private static final String EXPLORATORY_NAME = "exploratoryName";
-	private static final String COMPUTE_NAME = "computeName";
-	private static final String COMPUTE_NAME_2 = "computeName2";
-	private static final String CURRENCY = "currency";
-	private static final String PRODUCT = "product";
-	private static final String SHAPE = "shape";
-
-	private static final String SHARED_RESOURCE = "Shared resource";
-	private static final String SSN_ID = SERVICE_BASE_NAME + "-ssn";
-	private static final String SSN_VOLUME_ID = SERVICE_BASE_NAME + "-ssn" + "-volume-primary";
-	private static final String EDGE_ID_1 = SERVICE_BASE_NAME + "-" + PROJECT + "-" + ENDPOINT + "-edge";
-	private static final String EDGE_VOLUME_ID_1 = SERVICE_BASE_NAME + "-" + PROJECT + "-" + ENDPOINT + "-edge-volume-primary";
-	private static final String ENDPOINT_BUCKET_ID = SERVICE_BASE_NAME + "-" + PROJECT + "-" + ENDPOINT + "-bucket";
-	private static final String PROJECT_ENDPOINT_BUCKET_ID_1 = SERVICE_BASE_NAME + "-" + ENDPOINT + "-shared-bucket";
-	private static final String ENDPOINT_ID_1 = SERVICE_BASE_NAME + "-" + ENDPOINT + "-endpoint";
-	private static final String EXPLORATORY_ID = "exploratory_id";
-	private static final String EXPLORATORY_VOLUME_PRIMARY_ID_1 = EXPLORATORY_ID + "-volume-primary";
-	private static final String EXPLORATORY_SECONDARY_ID_1 = EXPLORATORY_ID + "-volume-secondary";
-	private static final String COMPUTE_ID = "compute_id";
-	private static final String COMPUTE_VOLUME_PRIMARY_ID = COMPUTE_ID + "-volume-primary";
-	private static final String COMPUTE_VOLUME_SECONDARY_ID = COMPUTE_ID + "-volume-secondary";
-	private static final String COMPUTE_MASTER_VOLUME_PRIMARY_ID = COMPUTE_ID + "-m" + "-volume-primary";
-	private static final String COMPUTE_MASTER_VOLUME_SECONDARY_ID = COMPUTE_ID + "-m" + "-volume-secondary";
-	private static final String COMPUTE_SLAVE_1_VOLUME_PRIMARY_ID = COMPUTE_ID + "-s1" + "-volume-primary";
-	private static final String COMPUTE_SLAVE_1_VOLUME_SECONDARY_ID = COMPUTE_ID + "-s1" + "-volume-secondary";
-	private static final String COMPUTE_SLAVE_2_VOLUME_PRIMARY_ID = COMPUTE_ID + "-s2" + "-volume-primary";
-	private static final String COMPUTE_SLAVE_2_VOLUME_SECONDARY_ID = COMPUTE_ID + "-s2" + "-volume-secondary";
-	private static final String IMAGE_ID = SERVICE_BASE_NAME + "-" + PROJECT + "-" + ENDPOINT + "-" + IMAGE_APPLICATION + "-" + IMAGE_NAME;
-
-	@Mock
-	private SelfServiceApplicationConfiguration configuration;
-	@Mock
-	private ProjectDAO projectDAO;
-	@Mock
-	private ProjectService projectService;
-	@Mock
-	private BillingDAO billingDAO;
-	@Mock
-	private EndpointService endpointService;
-	@Mock
-	private RESTService provisioningService;
-	@Mock
-	private ExploratoryService exploratoryService;
-	@Mock
-	private ImageExploratoryDAO imageExploratoryDAO;
-
-	@InjectMocks
-	private BillingServiceImpl billingService;
-
-	@Test
-	public void getBillingReport() {
-		when(billingDAO.aggregateBillingData(any(BillingFilter.class))).thenReturn(getBillingReportLineWithCost());
-		when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.FALSE));
-		when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
-		when(exploratoryService.getUserInstance(anyString(), anyString(), anyString())).thenReturn(Optional.of(getUserInstanceDTO()));
-		when(exploratoryService.getUserInstance(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(Optional.of(getUserInstanceDTOWithCompute()));
-
-		BillingReport actualBillingReport = billingService.getBillingReport(getUserInfo(), new BillingFilter());
-
-		assertEquals("reports should be equal", getExpectedBillingReport(), actualBillingReport);
-		verify(billingDAO).aggregateBillingData(new BillingFilter());
-		verify(projectService).get(PROJECT);
-		verify(exploratoryService).getUserInstance(USER, PROJECT, EXPLORATORY_NAME);
-		verify(exploratoryService).getUserInstance(USER, PROJECT, EXPLORATORY_NAME, Boolean.TRUE);
-		verifyNoMoreInteractions(billingDAO);
-	}
-
-	@Test
-	public void getBillingReportWithNullCurrency() {
-		when(billingDAO.aggregateBillingData(any(BillingFilter.class))).thenReturn(getBillingReportLineWithDifferentCurrency());
-		when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
-
-		BillingReport actualBillingReport = billingService.getBillingReport(getUserInfo(), new BillingFilter());
-
-		assertEquals("reports should be equal", getExpectedBillingReportWithNullCurrency(), actualBillingReport);
-		verify(billingDAO).aggregateBillingData(new BillingFilter());
-		verifyNoMoreInteractions(billingDAO);
-	}
-
-	@Test
-	public void downloadReport() {
-		when(billingDAO.aggregateBillingData(any(BillingFilter.class))).thenReturn(getBillingReportLineWithCost());
-		when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.FALSE));
-		when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
-		when(exploratoryService.getUserInstance(anyString(), anyString(), anyString())).thenReturn(Optional.of(getUserInstanceDTO()));
-		when(exploratoryService.getUserInstance(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(Optional.of(getUserInstanceDTOWithCompute()));
-
-		String actualBillingReport = billingService.downloadReport(getUserInfo(), new BillingFilter());
-
-		assertEquals("reports should be equal", getDownloadReport(), actualBillingReport);
-		verify(billingDAO).aggregateBillingData(new BillingFilter());
-		verify(projectService).get(PROJECT);
-		verify(exploratoryService).getUserInstance(USER, PROJECT, EXPLORATORY_NAME);
-		verify(exploratoryService).getUserInstance(USER, PROJECT, EXPLORATORY_NAME, Boolean.TRUE);
-		verifyNoMoreInteractions(billingDAO);
-	}
-
-	@Test
-	public void getExploratoryBillingData() {
-		when(billingDAO.findBillingData(anyString(), anyString(), anyListOf(String.class))).thenReturn(getBillingReportLineWithCost());
-
-		BillingReport actualReport = billingService.getExploratoryBillingData(PROJECT, ENDPOINT, EXPLORATORY_NAME, Arrays.asList(COMPUTE_NAME, COMPUTE_NAME_2));
-
-		assertEquals("reports should be equal", getReport(), actualReport);
-		verify(billingDAO).findBillingData(PROJECT, ENDPOINT, Arrays.asList(COMPUTE_NAME, COMPUTE_NAME_2, EXPLORATORY_NAME));
-		verifyNoMoreInteractions(billingDAO);
-	}
-
-	@Test
-	public void getExploratoryBillingDataWithNullCurrency() {
-		when(billingDAO.findBillingData(anyString(), anyString(), anyListOf(String.class))).thenReturn(getBillingReportLineWithDifferentCurrency());
-
-		BillingReport actualReport = billingService.getExploratoryBillingData(PROJECT, ENDPOINT, EXPLORATORY_NAME, Arrays.asList(COMPUTE_NAME, COMPUTE_NAME_2));
-
-		assertEquals("reports should be equal", getReportWithNullCurrency(), actualReport);
-		verify(billingDAO).findBillingData(PROJECT, ENDPOINT, Arrays.asList(COMPUTE_NAME, COMPUTE_NAME_2, EXPLORATORY_NAME));
-		verifyNoMoreInteractions(billingDAO);
-	}
-
-	@Test
-	public void updateGCPRemoteBillingData() {
-		when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
-		when(configuration.getMaxSparkInstanceCount()).thenReturn(2);
-		when(endpointService.getEndpoints()).thenReturn(getGCPEndpointDTO());
-		when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenReturn(getBillingData());
-		when(projectService.getProjects()).thenReturn(getProjectDTOs());
-		when(exploratoryService.findAll(anySet())).thenReturn(getUserInstanceDTOs());
-		when(imageExploratoryDAO.getImagesForProject(anyString())).thenReturn(getImageInfoRecords());
-
-		billingService.updateRemoteBillingData(getUserInfo());
-
-		verify(endpointService).getEndpoints();
-		verify(provisioningService).get(BILLING_URL, TOKEN, new GenericType<List<BillingData>>() {
-		});
-		verify(projectService).getProjects();
-		verify(exploratoryService).findAll(new HashSet<>(getProjectDTOs()));
-		verify(imageExploratoryDAO).getImagesForProject(PROJECT);
-		verify(billingDAO).deleteByUsageDateRegex(ENDPOINT, USAGE_DATE_FORMATTED);
-		verify(billingDAO).save(getBillingReportLine());
-		verifyNoMoreInteractions(endpointService, provisioningService, billingDAO, projectService, exploratoryService, imageExploratoryDAO);
-	}
-
-	@Test
-	public void updateAWSRemoteBillingData() {
-		when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
-		when(configuration.getMaxSparkInstanceCount()).thenReturn(2);
-		when(endpointService.getEndpoints()).thenReturn(getAWSEndpointDTO());
-		when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenReturn(getBillingData());
-		when(projectService.getProjects()).thenReturn(getProjectDTOs());
-		when(exploratoryService.findAll(anySet())).thenReturn(getUserInstanceDTOs());
-		when(imageExploratoryDAO.getImagesForProject(anyString())).thenReturn(getImageInfoRecords());
-
-		billingService.updateRemoteBillingData(getUserInfo());
-
-		verify(endpointService).getEndpoints();
-		verify(provisioningService).get(BILLING_URL, TOKEN, new GenericType<List<BillingData>>() {
-		});
-		verify(projectService).getProjects();
-		verify(exploratoryService).findAll(new HashSet<>(getProjectDTOs()));
-		verify(imageExploratoryDAO).getImagesForProject(PROJECT);
-		verify(billingDAO).deleteByUsageDate(ENDPOINT, USAGE_DATE);
-		verify(billingDAO).save(getBillingReportLine());
-		verifyNoMoreInteractions(endpointService, provisioningService, billingDAO, projectService, exploratoryService, imageExploratoryDAO);
-	}
-
-	@Test
-	public void updateAzureRemoteBillingData() {
-		when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
-		when(configuration.getMaxSparkInstanceCount()).thenReturn(2);
-		when(endpointService.getEndpoints()).thenReturn(getAzureEndpointDTO());
-		when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenReturn(getBillingData());
-		when(projectService.getProjects()).thenReturn(getProjectDTOs());
-		when(exploratoryService.findAll(anySet())).thenReturn(getUserInstanceDTOs());
-		when(imageExploratoryDAO.getImagesForProject(anyString())).thenReturn(getImageInfoRecords());
-
-		billingService.updateRemoteBillingData(getUserInfo());
-
-		verify(endpointService).getEndpoints();
-		verify(provisioningService).get(BILLING_URL, TOKEN, new GenericType<List<BillingData>>() {
-		});
-		verify(projectService).getProjects();
-		verify(exploratoryService).findAll(new HashSet<>(getProjectDTOs()));
-		verify(imageExploratoryDAO).getImagesForProject(PROJECT);
-		verify(billingDAO).save(getBillingReportLine());
-		verifyNoMoreInteractions(endpointService, provisioningService, billingDAO, projectService, exploratoryService, imageExploratoryDAO);
-	}
-
-	@Test(expected = DlabException.class)
-	public void updateRemoteBillingDataWithException1() {
-		when(endpointService.getEndpoints()).thenReturn(Collections.emptyList());
-
-		billingService.updateRemoteBillingData(getUserInfo());
-	}
-
-	@Test
-	public void updateRemoteBillingDataWithException2() {
-		when(endpointService.getEndpoints()).thenReturn(getAWSEndpointDTO());
-		when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenThrow(new DlabException("Exception message"));
-
-		billingService.updateRemoteBillingData(getUserInfo());
-
-		verify(endpointService).getEndpoints();
-		verify(provisioningService).get(BILLING_URL, TOKEN, new GenericType<List<BillingData>>() {
-		});
-		verifyNoMoreInteractions(endpointService, provisioningService, billingDAO, projectService, exploratoryService, imageExploratoryDAO);
-	}
-
-	@Test
-	public void updateRemoteBillingDataWithException3() {
-		when(endpointService.getEndpoints()).thenReturn(getEndpointDTOWithWrongUrl());
-
-		billingService.updateRemoteBillingData(getUserInfo());
-
-		verify(endpointService).getEndpoints();
-		verifyNoMoreInteractions(endpointService, provisioningService, billingDAO, projectService, exploratoryService, imageExploratoryDAO);
-	}
-
-	@Test
-	public void getQuotas() {
-		when(billingDAO.getBillingQuoteUsed()).thenReturn(50);
-		when(projectService.getProjects(any(UserInfo.class))).thenReturn(getProjectDTOs(Boolean.FALSE));
-		when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
-		when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.FALSE));
-		when(billingDAO.getOverallProjectCost(anyString())).thenReturn(5d);
-
-		QuotaUsageDTO quotas = billingService.getQuotas(getUserInfo());
-
-		assertEquals("QuotaUsageDTO should be equal", getQuotaUsageDTO(), quotas);
-		verify(billingDAO).getBillingQuoteUsed();
-		verify(projectService).getProjects(getUserInfo());
-		verify(projectDAO).getAllowedBudget(PROJECT);
-		verify(projectDAO).getAllowedBudget(PROJECT_2);
-		verify(projectService).get(PROJECT);
-		verify(projectService).get(PROJECT_2);
-		verify(billingDAO).getOverallProjectCost(PROJECT);
-		verify(billingDAO).getOverallProjectCost(PROJECT_2);
-		verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
-	}
-
-	@Test
-	public void getMonthlyQuotas() {
-		when(billingDAO.getBillingQuoteUsed()).thenReturn(50);
-		when(projectService.getProjects(any(UserInfo.class))).thenReturn(getProjectDTOs(Boolean.FALSE));
-		when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
-		when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.TRUE));
-		when(billingDAO.getMonthlyProjectCost(anyString(), any(LocalDate.class))).thenReturn(5d);
-
-		QuotaUsageDTO quotas = billingService.getQuotas(getUserInfo());
-
-		assertEquals("QuotaUsageDTO should be equal", getQuotaUsageDTO(), quotas);
-		verify(billingDAO).getBillingQuoteUsed();
-		verify(projectService).getProjects(getUserInfo());
-		verify(projectDAO).getAllowedBudget(PROJECT);
-		verify(projectDAO).getAllowedBudget(PROJECT_2);
-		verify(projectService).get(PROJECT);
-		verify(projectService).get(PROJECT_2);
-		verify(billingDAO).getMonthlyProjectCost(PROJECT, LocalDate.now());
-		verify(billingDAO).getMonthlyProjectCost(PROJECT_2, LocalDate.now());
-		verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
-	}
-
-	@Test
-	public void isProjectQuoteReached() {
-		when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
-		when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.FALSE));
-		when(billingDAO.getOverallProjectCost(anyString())).thenReturn(5d);
-
-		final boolean projectQuoteReached = billingService.isProjectQuoteReached(PROJECT);
-
-		assertEquals("quotes should be equal", Boolean.FALSE, projectQuoteReached);
-		verify(projectDAO).getAllowedBudget(PROJECT);
-		verify(projectService).get(PROJECT);
-		verify(billingDAO).getOverallProjectCost(PROJECT);
-		verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
-	}
-
-	@Test
-	public void isProjectQuoteNullReached() {
-		when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
-		when(projectService.get(anyString())).thenReturn(getProjectQuoteNullDTO());
-		when(billingDAO.getOverallProjectCost(anyString())).thenReturn(5d);
-
-		final boolean projectQuoteReached = billingService.isProjectQuoteReached(PROJECT);
-
-		assertEquals("quotes should be equal", Boolean.FALSE, projectQuoteReached);
-		verify(projectDAO).getAllowedBudget(PROJECT);
-		verify(projectService).get(PROJECT);
-		verify(billingDAO).getOverallProjectCost(PROJECT);
-		verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
-	}
-
-	@Test
-	public void isProjectMonthlyQuoteReached() {
-		when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
-		when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.TRUE));
-		when(billingDAO.getMonthlyProjectCost(anyString(), any(LocalDate.class))).thenReturn(5d);
-
-		final boolean projectQuoteReached = billingService.isProjectQuoteReached(PROJECT);
-
-		assertEquals("quotes should be equal", Boolean.FALSE, projectQuoteReached);
-		verify(projectDAO).getAllowedBudget(PROJECT);
-		verify(projectService).get(PROJECT);
-		verify(billingDAO).getMonthlyProjectCost(PROJECT, LocalDate.now());
-		verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
-	}
-
-	@Test
-	public void getBillingProjectQuoteUsed() {
-		when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
-		when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.FALSE));
-		when(billingDAO.getOverallProjectCost(anyString())).thenReturn(5d);
-
-		final int billingProjectQuoteUsed = billingService.getBillingProjectQuoteUsed(PROJECT);
-
-		assertEquals("quotes should be equal", 50, billingProjectQuoteUsed);
-		verify(projectDAO).getAllowedBudget(PROJECT);
-		verify(projectService).get(PROJECT);
-		verify(billingDAO).getOverallProjectCost(PROJECT);
-		verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
-	}
-
-	@Test
-	public void getBillingProjectQuoteNullUsed() {
-		when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
-		when(projectService.get(anyString())).thenReturn(getProjectQuoteNullDTO());
-		when(billingDAO.getOverallProjectCost(anyString())).thenReturn(5d);
-
-		final int billingProjectQuoteUsed = billingService.getBillingProjectQuoteUsed(PROJECT);
-
-		assertEquals("quotes should be equal", 50, billingProjectQuoteUsed);
-		verify(projectDAO).getAllowedBudget(PROJECT);
-		verify(projectService).get(PROJECT);
-		verify(billingDAO).getOverallProjectCost(PROJECT);
-		verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
-	}
-
-	@Test
-	public void getBillingProjectMonthlyQuoteUsed() {
-		when(projectDAO.getAllowedBudget(anyString())).thenReturn(Optional.of(10));
-		when(projectService.get(anyString())).thenReturn(getProjectDTO(Boolean.TRUE));
-		when(billingDAO.getMonthlyProjectCost(anyString(), any(LocalDate.class))).thenReturn(5d);
-
-		final int billingProjectQuoteUsed = billingService.getBillingProjectQuoteUsed(PROJECT);
-
-		assertEquals("quotes should be equal", 50, billingProjectQuoteUsed);
-		verify(projectDAO).getAllowedBudget(PROJECT);
-		verify(projectService).get(PROJECT);
-		verify(billingDAO).getMonthlyProjectCost(PROJECT, LocalDate.now());
-		verifyNoMoreInteractions(projectDAO, projectService, billingDAO);
-	}
-
-	private ProjectDTO getProjectDTO(boolean isMonthlyBudget) {
-		return ProjectDTO.builder()
-				.name(PROJECT)
-				.budget(new BudgetDTO(10, isMonthlyBudget))
-				.endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT, UserInstanceStatus.RUNNING, null)))
-				.build();
-	}
-
-	private List<ProjectDTO> getProjectDTOs(boolean isMonthlyBudget) {
-		ProjectDTO project1 = ProjectDTO.builder()
-				.name(PROJECT)
-				.budget(new BudgetDTO(10, isMonthlyBudget))
-				.endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT, UserInstanceStatus.RUNNING, null)))
-				.build();
-		ProjectDTO project2 = ProjectDTO.builder()
-				.name(PROJECT_2)
-				.budget(new BudgetDTO(20, isMonthlyBudget))
-				.endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT, UserInstanceStatus.RUNNING, null)))
-				.build();
-		return Arrays.asList(project1, project2);
-	}
-
-	private ProjectDTO getProjectQuoteNullDTO() {
-		return ProjectDTO.builder()
-				.name(PROJECT)
-				.endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT, UserInstanceStatus.RUNNING, null)))
-				.build();
-	}
-
-	private List<ProjectDTO> getProjectDTOs() {
-		return Collections.singletonList(ProjectDTO.builder()
-				.name(PROJECT)
-				.endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT, UserInstanceStatus.RUNNING, null)))
-				.build());
-	}
-
-	private QuotaUsageDTO getQuotaUsageDTO() {
-		Map<String, Integer> projectQuotas = new HashMap<>();
-		projectQuotas.put(PROJECT, 50);
-		projectQuotas.put(PROJECT_2, 50);
-		return QuotaUsageDTO.builder()
-				.totalQuotaUsed(50)
-				.projectQuotas(projectQuotas)
-				.build();
-	}
-
-	private List<BillingData> getBillingData() {
-		BillingData ssnID = BillingData.builder().tag(SSN_ID).usageDate(USAGE_DATE).build();
-		BillingData ssnVolumeID = BillingData.builder().tag(SSN_VOLUME_ID).usageDate(USAGE_DATE).build();
-
-		BillingData edgeID = BillingData.builder().tag(EDGE_ID_1).usageDate(USAGE_DATE).build();
-		BillingData edgeVolumeId = BillingData.builder().tag(EDGE_VOLUME_ID_1).usageDate(USAGE_DATE).build();
-		BillingData endpointBucketId = BillingData.builder().tag(ENDPOINT_BUCKET_ID).usageDate(USAGE_DATE).build();
-
-		BillingData projectEndpointBucketId = BillingData.builder().tag(PROJECT_ENDPOINT_BUCKET_ID_1).usageDate(USAGE_DATE).build();
-		BillingData endpointId = BillingData.builder().tag(ENDPOINT_ID_1).usageDate(USAGE_DATE).build();
-
-		BillingData exploratoryId = BillingData.builder().tag(EXPLORATORY_ID).usageDate(USAGE_DATE).build();
-		BillingData exploratoryPrimaryVolumeId = BillingData.builder().tag(EXPLORATORY_VOLUME_PRIMARY_ID_1).usageDate(USAGE_DATE).build();
-		BillingData exploratorySecondaryVolumeId = BillingData.builder().tag(EXPLORATORY_SECONDARY_ID_1).usageDate(USAGE_DATE).build();
-
-		BillingData computeId = BillingData.builder().tag(COMPUTE_ID).usageDate(USAGE_DATE).build();
-		BillingData computePrimaryVolumeId = BillingData.builder().tag(COMPUTE_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).build();
-		BillingData computeSecondaryVolumeId = BillingData.builder().tag(COMPUTE_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).build();
-		BillingData computeMasterPrimaryVolumeId = BillingData.builder().tag(COMPUTE_MASTER_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).build();
-		BillingData computeMasterSecondaryVolumeId = BillingData.builder().tag(COMPUTE_MASTER_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).build();
-		BillingData computeSlave1PrimaryVolumeId = BillingData.builder().tag(COMPUTE_SLAVE_1_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).build();
-		BillingData computeSlave1SecondaryVolumeId = BillingData.builder().tag(COMPUTE_SLAVE_1_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).build();
-		BillingData computeSlave2PrimaryVolumeId = BillingData.builder().tag(COMPUTE_SLAVE_2_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).build();
-		BillingData computeSlave2SecondaryVolumeId = BillingData.builder().tag(COMPUTE_SLAVE_2_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).build();
-
-		BillingData imageId = BillingData.builder().tag(IMAGE_ID).usageDate(USAGE_DATE).build();
-
-
-		return Arrays.asList(ssnID, ssnVolumeID, edgeID, edgeVolumeId, endpointBucketId, projectEndpointBucketId, endpointId, exploratoryId, exploratoryPrimaryVolumeId,
-				exploratorySecondaryVolumeId, computeId, computePrimaryVolumeId, computeSecondaryVolumeId, computeMasterPrimaryVolumeId, computeMasterSecondaryVolumeId,
-				computeSlave1PrimaryVolumeId, computeSlave1SecondaryVolumeId, computeSlave2PrimaryVolumeId, computeSlave2SecondaryVolumeId, imageId);
-	}
-
-	private List<BillingReportLine> getBillingReportLine() {
-		BillingReportLine ssn = BillingReportLine.builder().dlabId(SSN_ID).usageDate(USAGE_DATE).application(ENDPOINT).resourceName("SSN")
-				.user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceType(BillingResourceType.SSN).build();
-		BillingReportLine ssnVolume = BillingReportLine.builder().dlabId(SSN_VOLUME_ID).usageDate(USAGE_DATE).application(ENDPOINT).resourceName("SSN Volume")
-				.user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceType(BillingResourceType.VOLUME).build();
-
-		BillingReportLine edge = BillingReportLine.builder().dlabId(EDGE_ID_1).usageDate(USAGE_DATE).application(ENDPOINT).resourceName(ENDPOINT)
-				.user(SHARED_RESOURCE).project(PROJECT).resourceType(BillingResourceType.EDGE).build();
-		BillingReportLine edgeVolumeId = BillingReportLine.builder().dlabId(EDGE_VOLUME_ID_1).usageDate(USAGE_DATE).application(ENDPOINT).resourceName("EDGE volume")
-				.user(SHARED_RESOURCE).project(PROJECT).resourceType(BillingResourceType.VOLUME).build();
-		BillingReportLine endpointBucketId = BillingReportLine.builder().dlabId(ENDPOINT_BUCKET_ID).usageDate(USAGE_DATE).application(ENDPOINT).resourceName("Project endpoint shared bucket")
-				.user(SHARED_RESOURCE).project(PROJECT).resourceType(BillingResourceType.BUCKET).build();
-
-		BillingReportLine projectEndpointBucket = BillingReportLine.builder().dlabId(PROJECT_ENDPOINT_BUCKET_ID_1).usageDate(USAGE_DATE).application(ENDPOINT).resourceName("Endpoint shared bucket")
-				.user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceType(BillingResourceType.BUCKET).build();
-		BillingReportLine endpoint = BillingReportLine.builder().dlabId(ENDPOINT_ID_1).usageDate(USAGE_DATE).application(ENDPOINT).resourceName("Endpoint")
-				.user(SHARED_RESOURCE).project(SHARED_RESOURCE).resourceType(BillingResourceType.ENDPOINT).build();
-
-		BillingReportLine exploratory = BillingReportLine.builder().dlabId(EXPLORATORY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
-				.user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(EXPLORATORY_NAME).resourceType(BillingResourceType.EXPLORATORY).build();
-		BillingReportLine exploratoryPrimaryVolume = BillingReportLine.builder().dlabId(EXPLORATORY_VOLUME_PRIMARY_ID_1).usageDate(USAGE_DATE).application(ENDPOINT)
-				.user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(EXPLORATORY_NAME).resourceType(BillingResourceType.VOLUME).build();
-		BillingReportLine exploratorySecondaryVolume = BillingReportLine.builder().dlabId(EXPLORATORY_SECONDARY_ID_1).usageDate(USAGE_DATE).application(ENDPOINT)
-				.user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(EXPLORATORY_NAME).resourceType(BillingResourceType.VOLUME).build();
-
-		BillingReportLine compute = BillingReportLine.builder().dlabId(COMPUTE_ID).usageDate(USAGE_DATE).application(ENDPOINT).user(USER).project(PROJECT)
-				.endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.COMPUTATIONAL).shape("3 x " + SHAPE).exploratoryName(EXPLORATORY_NAME).build();
-		BillingReportLine computePrimaryVolume = BillingReportLine.builder().dlabId(COMPUTE_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).application(ENDPOINT).user(USER)
-				.project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
-		BillingReportLine computeSecondaryVolume = BillingReportLine.builder().dlabId(COMPUTE_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).application(ENDPOINT).user(USER)
-				.project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
-		BillingReportLine computeMasterPrimaryVolume = BillingReportLine.builder().dlabId(COMPUTE_MASTER_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
-				.user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
-		BillingReportLine computeMasterSecondaryVolume = BillingReportLine.builder().dlabId(COMPUTE_MASTER_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
-				.user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
-		BillingReportLine computeSlave1PrimaryVolume = BillingReportLine.builder().dlabId(COMPUTE_SLAVE_1_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
-				.user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
-		BillingReportLine computeSlave1SecondaryVolume = BillingReportLine.builder().dlabId(COMPUTE_SLAVE_1_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
-				.user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
-		BillingReportLine computeSlave2PrimaryVolume = BillingReportLine.builder().dlabId(COMPUTE_SLAVE_2_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
-				.user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
-		BillingReportLine computeSlave2SecondaryVolume = BillingReportLine.builder().dlabId(COMPUTE_SLAVE_2_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).application(ENDPOINT)
-				.user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
-
-		BillingReportLine image = BillingReportLine.builder().dlabId(IMAGE_ID).usageDate(USAGE_DATE).application(ENDPOINT)
-				.user(USER).project(PROJECT).resourceName(IMAGE_NAME).resourceType(BillingResourceType.IMAGE).build();
-
-		return Arrays.asList(ssn, ssnVolume, edge, edgeVolumeId, endpointBucketId, projectEndpointBucket, endpoint, exploratory, exploratoryPrimaryVolume,
-				exploratorySecondaryVolume, compute, computePrimaryVolume, computeSecondaryVolume, computeMasterPrimaryVolume, computeMasterSecondaryVolume,
-				computeSlave1PrimaryVolume, computeSlave1SecondaryVolume, computeSlave2PrimaryVolume, computeSlave2SecondaryVolume, image);
-	}
-
-	private List<BillingReportLine> getBillingReportLineWithCost() {
-		BillingReportLine line1 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-01-01")).usageDateTo(LocalDate.parse("2020-03-01")).cost(1.999)
-				.currency(CURRENCY).dlabId(EDGE_ID_1).user(USER).product(PRODUCT).shape(SHAPE).resourceType(BillingResourceType.EDGE).project(PROJECT)
-				.resourceName(ENDPOINT).build();
-		BillingReportLine line2 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-02-01")).usageDateTo(LocalDate.parse("2020-05-01")).cost(1.0)
-				.currency(CURRENCY).dlabId(EXPLORATORY_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.EXPLORATORY).project(PROJECT)
-				.resourceName(EXPLORATORY_NAME).build();
-		BillingReportLine line3 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-03-01")).usageDateTo(LocalDate.parse("2020-04-01")).cost(1.0)
-				.currency(CURRENCY).dlabId(COMPUTE_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.COMPUTATIONAL).project(PROJECT)
-				.resourceName(COMPUTE_NAME)
-				.exploratoryName(EXPLORATORY_NAME).build();
-
-		return Arrays.asList(line1, line2, line3);
-	}
-
-	private List<BillingReportLine> getBillingReportLineWithDifferentCurrency() {
-		BillingReportLine line1 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-01-01")).usageDateTo(LocalDate.parse("2020-03-01")).cost(1.999)
-				.currency(CURRENCY).build();
-		BillingReportLine line2 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-02-01")).usageDateTo(LocalDate.parse("2020-05-01")).cost(1.0)
-				.currency("currency2").build();
-		BillingReportLine line3 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-03-01")).usageDateTo(LocalDate.parse("2020-04-01")).cost(1.0)
-				.currency(CURRENCY).build();
-
-		return Arrays.asList(line1, line2, line3);
-	}
-
-	private BillingReport getReport() {
-		BillingReportLine line1 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-01-01")).usageDateTo(LocalDate.parse("2020-03-01")).cost(2.0)
-				.currency(CURRENCY).dlabId(EDGE_ID_1).user(USER).product(PRODUCT).shape(SHAPE).resourceType(BillingResourceType.EDGE).project(PROJECT)
-				.resourceName(ENDPOINT).build();
-		BillingReportLine line2 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-02-01")).usageDateTo(LocalDate.parse("2020-05-01")).cost(1.0)
-				.currency(CURRENCY).dlabId(EXPLORATORY_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.EXPLORATORY).project(PROJECT)
-				.resourceName(EXPLORATORY_NAME).build();
-		BillingReportLine line3 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-03-01")).usageDateTo(LocalDate.parse("2020-04-01")).cost(1.0)
-				.currency(CURRENCY).dlabId(COMPUTE_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.COMPUTATIONAL).project(PROJECT)
-				.resourceName(COMPUTE_NAME).exploratoryName(EXPLORATORY_NAME).build();
-		List<BillingReportLine> billingReportLines = Arrays.asList(line1, line2, line3);
-
-		return BillingReport.builder()
-				.name(EXPLORATORY_NAME)
-				.reportLines(billingReportLines)
-				.totalCost(4.0)
-				.currency(CURRENCY)
-				.build();
-	}
-
-	private BillingReport getReportWithNullCurrency() {
-		BillingReportLine line1 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-01-01")).usageDateTo(LocalDate.parse("2020-03-01")).cost(2.0)
-				.currency(CURRENCY).build();
-		BillingReportLine line2 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-02-01")).usageDateTo(LocalDate.parse("2020-05-01")).cost(1.0)
-				.currency("currency2").build();
-		BillingReportLine line3 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-03-01")).usageDateTo(LocalDate.parse("2020-04-01")).cost(1.0)
-				.currency(CURRENCY).build();
-		List<BillingReportLine> billingReportLines = Arrays.asList(line1, line2, line3);
-
-		return BillingReport.builder()
-				.name(EXPLORATORY_NAME)
-				.reportLines(billingReportLines)
-				.totalCost(4.0)
-				.currency(null)
-				.build();
-	}
-
-	private BillingReport getExpectedBillingReport() {
-		BillingReportLine line1 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-01-01")).usageDateTo(LocalDate.parse("2020-03-01")).cost(1.999)
-				.currency(CURRENCY).dlabId(EDGE_ID_1).user(USER).product(PRODUCT).shape(SHAPE).resourceType(BillingResourceType.EDGE).project(PROJECT)
-				.resourceName(ENDPOINT).status(UserInstanceStatus.RUNNING).build();
-		BillingReportLine line2 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-02-01")).usageDateTo(LocalDate.parse("2020-05-01")).cost(1.0)
-				.currency(CURRENCY).dlabId(EXPLORATORY_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.EXPLORATORY).project(PROJECT)
-				.resourceName(EXPLORATORY_NAME).status(UserInstanceStatus.FAILED).build();
-		BillingReportLine line3 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-03-01")).usageDateTo(LocalDate.parse("2020-04-01")).cost(1.0)
-				.currency(CURRENCY).dlabId(COMPUTE_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.COMPUTATIONAL).project(PROJECT)
-				.resourceName(COMPUTE_NAME).exploratoryName(EXPLORATORY_NAME).status(UserInstanceStatus.CREATING).build();
-		List<BillingReportLine> billingReportLines = Arrays.asList(line1, line2, line3);
-
-		return BillingReport.builder()
-				.name("Billing report")
-				.sbn(SERVICE_BASE_NAME)
-				.reportLines(billingReportLines)
-				.usageDateFrom(LocalDate.parse("2020-01-01"))
-				.usageDateTo(LocalDate.parse("2020-05-01"))
-				.totalCost(4.0)
-				.currency(CURRENCY)
-				.isReportHeaderCompletable(Boolean.TRUE)
-				.build();
-	}
-
-	private BillingReport getExpectedBillingReportWithNullCurrency() {
-		return BillingReport.builder()
-				.name("Billing report")
-				.sbn(SERVICE_BASE_NAME)
-				.reportLines(getBillingReportLineWithDifferentCurrency())
-				.usageDateFrom(LocalDate.parse("2020-01-01"))
-				.usageDateTo(LocalDate.parse("2020-05-01"))
-				.totalCost(4.0)
-				.currency(null)
-				.isReportHeaderCompletable(Boolean.TRUE)
-				.build();
-	}
-
-	private String getDownloadReport() {
-		StringBuilder sb = new StringBuilder();
-		sb.append("\"Service base name: ").append(SERVICE_BASE_NAME).append(". Available reporting period from: ").append(LocalDate.parse("2020-01-01"))
-				.append(" to: ").append(LocalDate.parse("2020-05-01")).append("\"\n");
-
-		sb.append(new StringJoiner(",").add("DLab ID").add("User").add("Project").add("DLab Resource Type").add("Status").add("Shape").add("Product")
-				.add("Cost\n").toString());
-
-		sb.append(new StringJoiner(",").add(EDGE_ID_1).add(USER).add(PROJECT).add("Edge").add("running").add(SHAPE).add(PRODUCT).add(1.999 + "\n"));
-		sb.append(new StringJoiner(",").add(EXPLORATORY_ID).add(USER).add(PROJECT).add("Exploratory").add("failed").add(SHAPE).add(PRODUCT).add(1.0 + "\n"));
-		sb.append(new StringJoiner(",").add(COMPUTE_ID).add(USER).add(PROJECT).add("Computational").add("creating").add(SHAPE).add(PRODUCT).add(1.0 + "\n"));
-
-		sb.append(",,,,,,,Total: 4.0 currency\n");
-
-		return sb.toString();
-	}
-
-	private List<EndpointDTO> getGCPEndpointDTO() {
-		return Collections.singletonList(new EndpointDTO(ENDPOINT, ENDPOINT_URL, ENDPOINT_ACCOUNT, ENDPOINT_TAG, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.GCP));
-	}
-
-	private List<EndpointDTO> getAWSEndpointDTO() {
-		return Collections.singletonList(new EndpointDTO(ENDPOINT, ENDPOINT_URL, ENDPOINT_ACCOUNT, ENDPOINT_TAG, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS));
-	}
-
-	private List<EndpointDTO> getAzureEndpointDTO() {
-		return Collections.singletonList(new EndpointDTO(ENDPOINT, ENDPOINT_URL, ENDPOINT_ACCOUNT, ENDPOINT_TAG, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AZURE));
-	}
-
-	private List<EndpointDTO> getEndpointDTOWithWrongUrl() {
-		return Collections.singletonList(new EndpointDTO(ENDPOINT, "wrong url", ENDPOINT_ACCOUNT, ENDPOINT_TAG, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AZURE));
-	}
-
-	private List<UserInstanceDTO> getUserInstanceDTOs() {
-		return Collections.singletonList(
-				new UserInstanceDTO().withExploratoryId(EXPLORATORY_ID).withUser(USER).withProject(PROJECT).withExploratoryName(EXPLORATORY_NAME).withEndpoint(ENDPOINT)
-						.withResources(Collections.singletonList(getCompute())));
-	}
-
-	private UserInstanceDTO getUserInstanceDTO() {
-		return new UserInstanceDTO().withExploratoryId(EXPLORATORY_ID).withUser(USER).withProject(PROJECT).withExploratoryName(EXPLORATORY_NAME).withEndpoint(ENDPOINT)
-				.withStatus("failed");
-	}
-
-	private UserInstanceDTO getUserInstanceDTOWithCompute() {
-		return new UserInstanceDTO().withExploratoryId(EXPLORATORY_ID).withUser(USER).withProject(PROJECT).withExploratoryName(EXPLORATORY_NAME).withEndpoint(ENDPOINT)
-				.withStatus("failed").withResources(Collections.singletonList(getCompute()));
-	}
-
-	private UserComputationalResource getCompute() {
-		UserComputationalResource resource = new UserComputationalResource();
-		resource.setComputationalId(COMPUTE_ID);
-		resource.setComputationalName(COMPUTE_NAME);
-		resource.setImageName(DataEngineType.SPARK_STANDALONE.getName());
-		resource.setDataengineInstanceCount(3);
-		resource.setDataengineShape(SHAPE);
-		resource.setStatus("creating");
-
-		return resource;
-	}
-
-	private List<ImageInfoRecord> getImageInfoRecords() {
-		return Collections.singletonList(
-				new ImageInfoRecord(IMAGE_NAME, IMAGE_DESCRIPTION, PROJECT, ENDPOINT, USER, IMAGE_APPLICATION, IMAGE_FULL_NAME, ImageStatus.CREATED)
-		);
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/BucketServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/BucketServiceImplTest.java
deleted file mode 100644
index 641100d..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/BucketServiceImplTest.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * 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.domain.EndpointDTO;
-import com.epam.dlab.backendapi.resources.TestBase;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.dto.bucket.BucketDTO;
-import com.epam.dlab.dto.bucket.BucketDeleteDTO;
-import com.epam.dlab.dto.bucket.FolderUploadDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import org.apache.http.HttpStatus;
-import org.glassfish.jersey.media.multipart.FormDataMultiPart;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.Response;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collections;
-import java.util.List;
-
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class BucketServiceImplTest extends TestBase {
-	private static final String BUCKET_GET_OBJECTS = "%sbucket/%s";
-	private static final String BUCKET_UPLOAD_OBJECT = "%sbucket/upload";
-	private static final String BUCKET_UPLOAD_FOLDER = "%sbucket/folder/upload";
-	private static final String BUCKET_DOWNLOAD_OBJECT = "%sbucket/%s/object/%s/download";
-	private static final String BUCKET_DELETE_OBJECT = "%sbucket/objects/delete";
-	private static final String BUCKET = "bucket";
-	private static final String OBJECT = "object";
-	private static final String SIZE = "size";
-	private static final String DATE = "date";
-	private static final String FOLDER = "folder/";
-
-	@Mock
-	private EndpointService endpointService;
-	@Mock
-	private RESTService provisioningService;
-	@InjectMocks
-	private BucketServiceImpl bucketService;
-
-	@Test
-	public void getObjects() {
-		EndpointDTO endpointDTO = getEndpointDTO();
-		List<BucketDTO> objects = getBucketList();
-		when(endpointService.get(anyString())).thenReturn(endpointDTO);
-		when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenReturn(objects);
-
-		List<BucketDTO> actualObjects = bucketService.getObjects(getUserInfo(), BUCKET, ENDPOINT_NAME);
-
-		assertEquals("lists should be equal", objects, actualObjects);
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).get(String.format(BUCKET_GET_OBJECTS, ENDPOINT_URL, BUCKET), TOKEN, new GenericType<List<BucketDTO>>() {
-		});
-		verifyNoMoreInteractions(endpointService, provisioningService);
-	}
-
-	@Test(expected = DlabException.class)
-	public void getObjectsWithException() {
-		EndpointDTO endpointDTO = getEndpointDTO();
-		when(endpointService.get(anyString())).thenReturn(endpointDTO);
-		when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenThrow(new DlabException("Exception message"));
-
-		bucketService.getObjects(getUserInfo(), BUCKET, ENDPOINT_NAME);
-
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).get(String.format(BUCKET_GET_OBJECTS, ENDPOINT_URL, BUCKET), TOKEN, new GenericType<List<BucketDTO>>() {
-		});
-
-		verifyNoMoreInteractions(endpointService, provisioningService);
-	}
-
-	@Test
-	public void uploadObject() {
-		EndpointDTO endpointDTO = getEndpointDTO();
-		Response response = Response.ok().build();
-		when(endpointService.get(anyString())).thenReturn(endpointDTO);
-		when(provisioningService.postForm(anyString(), anyString(), any(FormDataMultiPart.class), any())).thenReturn(response);
-
-		bucketService.uploadObject(getUserInfo(), BUCKET, OBJECT, ENDPOINT_NAME, getInputStream(), APPLICATION_JSON, 0, null);
-
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).postForm(eq(String.format(BUCKET_UPLOAD_OBJECT, ENDPOINT_URL)), eq(TOKEN), any(FormDataMultiPart.class), eq(Response.class));
-		verifyNoMoreInteractions(endpointService, provisioningService);
-	}
-
-	@Test(expected = DlabException.class)
-	public void uploadObjectWithException1() {
-		EndpointDTO endpointDTO = getEndpointDTO();
-		Response response = Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).build();
-		when(endpointService.get(anyString())).thenReturn(endpointDTO);
-		when(provisioningService.postForm(anyString(), anyString(), any(FormDataMultiPart.class), any())).thenReturn(response);
-
-		bucketService.uploadObject(getUserInfo(), BUCKET, OBJECT, ENDPOINT_NAME, getInputStream(), APPLICATION_JSON, 0, null);
-
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).postForm(eq(String.format(BUCKET_UPLOAD_OBJECT, ENDPOINT_URL)), eq(TOKEN), any(FormDataMultiPart.class), eq(Response.class));
-		verifyNoMoreInteractions(endpointService, provisioningService);
-	}
-
-	@Test(expected = DlabException.class)
-	public void uploadObjectWithException2() {
-		EndpointDTO endpointDTO = getEndpointDTO();
-		when(endpointService.get(anyString())).thenReturn(endpointDTO);
-
-		bucketService.uploadObject(getUserInfo(), BUCKET, OBJECT, ENDPOINT_NAME, null, APPLICATION_JSON, 0, null);
-
-		verify(endpointService).get(ENDPOINT_NAME);
-		verifyNoMoreInteractions(endpointService, provisioningService);
-	}
-
-	@Test
-	public void uploadFolder() {
-		EndpointDTO endpointDTO = getEndpointDTO();
-		Response response = Response.ok().build();
-		when(endpointService.get(anyString())).thenReturn(endpointDTO);
-		when(provisioningService.post(anyString(), anyString(), any(FolderUploadDTO.class), any())).thenReturn(response);
-
-		bucketService.uploadFolder(getUserInfo(), BUCKET, FOLDER, ENDPOINT_NAME, null);
-
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).post(eq(String.format(BUCKET_UPLOAD_FOLDER, ENDPOINT_URL)), eq(TOKEN), eq(getFolderUploadDTO()), eq(Response.class));
-		verifyNoMoreInteractions(endpointService, provisioningService);
-	}
-
-	@Test(expected = DlabException.class)
-	public void uploadFolderWithException1() {
-		EndpointDTO endpointDTO = getEndpointDTO();
-		Response response = Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).build();
-		when(endpointService.get(anyString())).thenReturn(endpointDTO);
-		when(provisioningService.post(anyString(), anyString(), any(FolderUploadDTO.class), any())).thenReturn(response);
-
-		bucketService.uploadFolder(getUserInfo(), BUCKET, FOLDER, ENDPOINT_NAME, null);
-
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).post(eq(String.format(BUCKET_UPLOAD_FOLDER, ENDPOINT_URL)), eq(TOKEN), eq(getFolderUploadDTO()), eq(Response.class));
-		verifyNoMoreInteractions(endpointService, provisioningService);
-	}
-
-	@Test(expected = DlabException.class)
-	public void uploadFolderWithException2() {
-		bucketService.uploadFolder(getUserInfo(), BUCKET, "folder_name_without_slash", ENDPOINT_NAME, null);
-	}
-
-	@Test
-	public void downloadObject() throws IOException {
-		EndpointDTO endpointDTO = getEndpointDTO();
-		HttpServletResponse response = mock(HttpServletResponse.class);
-		ServletOutputStream outputStream = mock(ServletOutputStream.class);
-		when(endpointService.get(anyString())).thenReturn(endpointDTO);
-		when(provisioningService.getWithMediaTypes(anyString(), anyString(), any(), anyString(), anyString())).thenReturn(getInputStream());
-		when(response.getOutputStream()).thenReturn(outputStream);
-
-		bucketService.downloadObject(getUserInfo(), BUCKET, OBJECT, ENDPOINT_NAME, response, null);
-
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).getWithMediaTypes(eq(String.format(BUCKET_DOWNLOAD_OBJECT, ENDPOINT_URL, BUCKET, OBJECT)), eq(TOKEN), eq(InputStream.class),
-				eq(APPLICATION_JSON), eq(APPLICATION_OCTET_STREAM));
-		verifyNoMoreInteractions(endpointService, provisioningService);
-	}
-
-	@Test(expected = DlabException.class)
-	public void downloadObjectWithException() {
-		EndpointDTO endpointDTO = getEndpointDTO();
-		HttpServletResponse response = mock(HttpServletResponse.class);
-		when(endpointService.get(anyString())).thenReturn(endpointDTO);
-		when(provisioningService.getWithMediaTypes(anyString(), anyString(), any(), anyString(), anyString())).thenThrow(new DlabException("Exception message"));
-
-		bucketService.downloadObject(getUserInfo(), BUCKET, OBJECT, ENDPOINT_NAME, response, null);
-
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).getWithMediaTypes(eq(String.format(BUCKET_DOWNLOAD_OBJECT, ENDPOINT_URL, BUCKET, OBJECT)), eq(TOKEN), eq(InputStream.class),
-				eq(APPLICATION_JSON), eq(APPLICATION_OCTET_STREAM));
-		verifyNoMoreInteractions(endpointService, provisioningService);
-	}
-
-	@Test
-	public void deleteObjects() {
-		EndpointDTO endpointDTO = getEndpointDTO();
-		Response response = Response.ok().build();
-		when(endpointService.get(anyString())).thenReturn(endpointDTO);
-		when(provisioningService.post(anyString(), anyString(), any(BucketDeleteDTO.class), any())).thenReturn(response);
-
-		bucketService.deleteObjects(getUserInfo(), BUCKET, Collections.singletonList(OBJECT), ENDPOINT_NAME, null);
-
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).post(eq(String.format(BUCKET_DELETE_OBJECT, ENDPOINT_URL)), eq(TOKEN), eq(getBucketDeleteDTO()), eq(Response.class));
-		verifyNoMoreInteractions(endpointService, provisioningService);
-	}
-
-	@Test(expected = DlabException.class)
-	public void deleteObjectsWithException() {
-		EndpointDTO endpointDTO = getEndpointDTO();
-		Response response = Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).build();
-		when(endpointService.get(anyString())).thenReturn(endpointDTO);
-		when(provisioningService.post(anyString(), anyString(), any(BucketDeleteDTO.class), any())).thenReturn(response);
-
-		bucketService.deleteObjects(getUserInfo(), BUCKET, Collections.singletonList(OBJECT), ENDPOINT_NAME, null);
-
-		verify(endpointService).get(ENDPOINT_NAME);
-		verify(provisioningService).post(eq(String.format(BUCKET_DELETE_OBJECT, ENDPOINT_URL)), eq(TOKEN), eq(getBucketDeleteDTO()), eq(Response.class));
-		verifyNoMoreInteractions(endpointService, provisioningService);
-	}
-
-	private List<BucketDTO> getBucketList() {
-		return Collections.singletonList(BucketDTO.builder()
-				.bucket(BUCKET)
-				.object(OBJECT)
-				.size(SIZE)
-				.lastModifiedDate(DATE)
-				.build());
-	}
-
-	private FolderUploadDTO getFolderUploadDTO() {
-		return new FolderUploadDTO(BUCKET, FOLDER);
-	}
-
-	private BucketDeleteDTO getBucketDeleteDTO() {
-		return new BucketDeleteDTO(BUCKET, Collections.singletonList(OBJECT));
-	}
-
-	private ByteArrayInputStream getInputStream() {
-		return new ByteArrayInputStream("input stream".getBytes());
-	}
-}
\ No newline at end of file
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
deleted file mode 100644
index bf4887e..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImplTest.java
+++ /dev/null
@@ -1,784 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.ComputationalDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-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.resources.dto.ComputationalCreateFormDTO;
-import com.epam.dlab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.backendapi.service.TagService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.SchedulerJobDTO;
-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.base.computational.ComputationalBase;
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-import com.epam.dlab.dto.computational.ComputationalClusterConfigDTO;
-import com.epam.dlab.dto.computational.ComputationalStartDTO;
-import com.epam.dlab.dto.computational.ComputationalStatusDTO;
-import com.epam.dlab.dto.computational.ComputationalStopDTO;
-import com.epam.dlab.dto.computational.ComputationalTerminateDTO;
-import com.epam.dlab.dto.computational.SparkStandaloneClusterResource;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.contracts.ComputationalAPI;
-import com.mongodb.client.result.UpdateResult;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.time.LocalDateTime;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-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 com.epam.dlab.rest.contracts.ComputationalAPI.AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE;
-import static java.util.Collections.singletonList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyListOf;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-
-@RunWith(MockitoJUnitRunner.class)
-public class ComputationalServiceImplTest {
-
-    private static final long MAX_INACTIVITY = 10L;
-    private static final String DOCKER_DLAB_DATAENGINE = "docker.dlab-dataengine";
-    private static final String DOCKER_DLAB_DATAENGINE_SERVICE = "docker.dlab-dataengine-service";
-    private static final String COMP_ID = "compId";
-    private final String USER = "test";
-    private final String TOKEN = "token";
-    private final String EXPLORATORY_NAME = "expName";
-    private final String PROJECT = "project";
-    private final String COMP_NAME = "compName";
-    private final String NOTE_BOOK_NAME = "notebookName";
-    private final String UUID = "1234-56789765-4321";
-    private final LocalDateTime LAST_ACTIVITY = LocalDateTime.now().minusMinutes(MAX_INACTIVITY);
-
-    private UserInfo userInfo;
-    private List<ComputationalCreateFormDTO> formList;
-    private UserInstanceDTO userInstance;
-    private ComputationalStatusDTO computationalStatusDTOWithStatusTerminating;
-    private ComputationalStatusDTO computationalStatusDTOWithStatusFailed;
-    private ComputationalStatusDTO computationalStatusDTOWithStatusStopping;
-    private ComputationalStatusDTO computationalStatusDTOWithStatusStarting;
-    private SparkStandaloneClusterResource sparkClusterResource;
-    private UserComputationalResource ucResource;
-
-    @Mock
-    private ProjectService projectService;
-    @Mock
-    private ExploratoryDAO exploratoryDAO;
-    @Mock
-    private ComputationalDAO computationalDAO;
-	@Mock
-	private RESTService provisioningService;
-	@Mock
-	private SelfServiceApplicationConfiguration configuration;
-	@Mock
-	private RequestBuilder requestBuilder;
-	@Mock
-	private RequestId requestId;
-	@Mock
-	private TagService tagService;
-	@Mock
-	private EndpointService endpointService;
-
-	@InjectMocks
-	private ComputationalServiceImpl computationalService;
-
-	@Rule
-	public ExpectedException expectedException = ExpectedException.none();
-
-	@Before
-	public void setUp() {
-		userInfo = getUserInfo();
-		userInstance = getUserInstanceDto();
-		formList = getFormList();
-		computationalStatusDTOWithStatusTerminating = getComputationalStatusDTOWithStatus("terminating");
-		computationalStatusDTOWithStatusFailed = getComputationalStatusDTOWithStatus("failed");
-		computationalStatusDTOWithStatusStopping = getComputationalStatusDTOWithStatus("stopping");
-		computationalStatusDTOWithStatusStarting = getComputationalStatusDTOWithStatus("starting");
-		sparkClusterResource = getSparkClusterResource();
-		ucResource = getUserComputationalResource(STOPPED, DOCKER_DLAB_DATAENGINE);
-	}
-
-	@Test
-	public void createSparkCluster() {
-        ProjectDTO projectDTO = getProjectDTO();
-        when(projectService.get(anyString())).thenReturn(projectDTO);
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(computationalDAO.addComputational(anyString(), anyString(), anyString(),
-                any(SparkStandaloneClusterResource.class))).thenReturn(true);
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-
-        ComputationalBase compBaseMocked = mock(ComputationalBase.class);
-        when(requestBuilder.newComputationalCreate(any(UserInfo.class), any(ProjectDTO.class),
-                any(UserInstanceDTO.class), any(SparkStandaloneClusterCreateForm.class), any(EndpointDTO.class)))
-                .thenReturn(compBaseMocked);
-        when(provisioningService.post(anyString(), anyString(), any(ComputationalBase.class), any())).thenReturn(UUID);
-        when(requestId.put(anyString(), anyString())).thenReturn(UUID);
-
-        SparkStandaloneClusterCreateForm form = (SparkStandaloneClusterCreateForm) formList.get(0);
-        boolean creationResult = computationalService.createSparkCluster(userInfo, form.getName(), form, PROJECT,
-                String.format(AUDIT_MESSAGE, form.getNotebookName()));
-        assertTrue(creationResult);
-
-        verify(projectService).get(PROJECT);
-        verify(computationalDAO).addComputational(eq(USER), eq(EXPLORATORY_NAME), eq(PROJECT), refEq(sparkClusterResource));
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(requestBuilder).newComputationalCreate(
-                refEq(userInfo), refEq(projectDTO), refEq(userInstance), refEq(form), refEq(endpointDTO()));
-
-        verify(provisioningService)
-                .post(endpointDTO().getUrl() + ComputationalAPI.COMPUTATIONAL_CREATE_SPARK, TOKEN, compBaseMocked,
-                        String.class);
-
-        verify(requestId).put(USER, UUID);
-        verifyNoMoreInteractions(projectService, configuration, computationalDAO, requestBuilder, provisioningService, requestId);
-    }
-
-    @Test
-    public void createSparkClusterWhenResourceAlreadyExists() {
-        when(computationalDAO.addComputational(anyString(), anyString(), anyString(),
-                any(SparkStandaloneClusterResource.class))).thenReturn(false);
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-
-        SparkStandaloneClusterCreateForm form = (SparkStandaloneClusterCreateForm) formList.get(0);
-        boolean creationResult = computationalService.createSparkCluster(userInfo, form.getName(), form, PROJECT,
-                String.format(AUDIT_MESSAGE, form.getNotebookName()));
-        assertFalse(creationResult);
-        verify(computationalDAO).addComputational(eq(USER), eq(EXPLORATORY_NAME), eq(PROJECT), refEq(sparkClusterResource));
-        verifyNoMoreInteractions(configuration, computationalDAO);
-    }
-
-	@Test
-	public void createSparkClusterWhenMethodFetchExploratoryFieldsThrowsException() {
-        when(computationalDAO.addComputational(anyString(), anyString(), anyString(),
-                any(SparkStandaloneClusterResource.class))).thenReturn(true);
-        doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
-                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
-
-        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
-                .thenReturn(mock(UpdateResult.class));
-
-        SparkStandaloneClusterCreateForm form = (SparkStandaloneClusterCreateForm) formList.get(0);
-        try {
-            computationalService.createSparkCluster(userInfo, form.getName(), form, PROJECT, String.format(AUDIT_MESSAGE, form.getNotebookName()));
-        } catch (ResourceNotFoundException e) {
-            assertEquals("Exploratory for user with name not found", e.getMessage());
-        }
-
-        verify(computationalDAO, never()).addComputational(USER, EXPLORATORY_NAME, PROJECT, sparkClusterResource);
-        verify(computationalDAO, never()).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed,
-                "self"));
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verifyNoMoreInteractions(configuration, computationalDAO, exploratoryDAO);
-    }
-
-	@Test
-	public void createSparkClusterWhenMethodNewComputationalCreateThrowsException() {
-        ProjectDTO projectDTO = getProjectDTO();
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(projectService.get(anyString())).thenReturn(projectDTO);
-        when(computationalDAO.addComputational(anyString(), anyString(), anyString(),
-                any(SparkStandaloneClusterResource.class))).thenReturn(true);
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-
-        doThrow(new DlabException("Cannot create instance of resource class "))
-                .when(requestBuilder).newComputationalCreate(any(UserInfo.class), any(ProjectDTO.class),
-                any(UserInstanceDTO.class), any(SparkStandaloneClusterCreateForm.class), any(EndpointDTO.class));
-
-        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
-                .thenReturn(mock(UpdateResult.class));
-
-        SparkStandaloneClusterCreateForm form = (SparkStandaloneClusterCreateForm) formList.get(0);
-        try {
-            computationalService.createSparkCluster(userInfo, form.getName(), form, PROJECT, String.format(AUDIT_MESSAGE, form.getNotebookName()));
-        } catch (DlabException e) {
-            assertEquals("Cannot create instance of resource class ", e.getMessage());
-        }
-        verify(projectService).get(PROJECT);
-        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, form, endpointDTO());
-        verifyNoMoreInteractions(projectService, configuration, computationalDAO, exploratoryDAO, requestBuilder);
-    }
-
-	@Test
-	public void terminateComputationalEnvironment() {
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
-                .thenReturn(mock(UpdateResult.class));
-        String explId = "explId";
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-
-        String compId = "compId";
-        UserComputationalResource ucResource = new UserComputationalResource();
-        ucResource.setComputationalName(COMP_NAME);
-        ucResource.setImageName("dataengine-service");
-        ucResource.setComputationalId(compId);
-        when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString())).thenReturn(ucResource);
-
-        ComputationalTerminateDTO ctDto = new ComputationalTerminateDTO();
-        ctDto.setComputationalName(COMP_NAME);
-        ctDto.setExploratoryName(EXPLORATORY_NAME);
-        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, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, AUDIT_MESSAGE);
-
-        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating, "self"));
-        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
-
-        verify(requestBuilder).newComputationalTerminate(userInfo.getName(), userInstance, ucResource, endpointDTO());
-
-        verify(provisioningService).post(endpointDTO().getUrl() + ComputationalAPI.COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC, TOKEN, ctDto,
-                String.class);
-
-        verify(requestId).put(USER, UUID);
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verifyNoMoreInteractions(computationalDAO, exploratoryDAO, requestBuilder, provisioningService, requestId);
-    }
-
-	@Test
-	public void terminateComputationalEnvironmentWhenMethodUpdateComputationalStatusThrowsException() {
-		doThrow(new DlabException("Could not update computational resource status"))
-				.when(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating,
-				"self"));
-
-		when(computationalDAO.updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self")))
-				.thenReturn(mock(UpdateResult.class));
-
-        try {
-            computationalService.terminateComputational(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, AUDIT_MESSAGE);
-        } catch (DlabException e) {
-            assertEquals("Could not update computational resource status", e.getMessage());
-        }
-
-		verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating, "self"));
-		verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
-		verifyNoMoreInteractions(computationalDAO);
-	}
-
-	@Test
-	public void terminateComputationalEnvironmentWhenMethodFetchComputationalFieldsThrowsException() {
-        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
-                .thenReturn(mock(UpdateResult.class));
-
-        doThrow(new DlabException("Computational resource for user with exploratory name not found."))
-                .when(computationalDAO).fetchComputationalFields(anyString(), anyString(), anyString(), anyString());
-        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
-                .thenReturn(mock(UpdateResult.class));
-
-        try {
-            computationalService.terminateComputational(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, AUDIT_MESSAGE);
-        } catch (DlabException e) {
-            assertEquals("Computational resource for user with exploratory name not found.", e.getMessage());
-        }
-
-        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating, "self"));
-        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
-        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verifyNoMoreInteractions(computationalDAO, exploratoryDAO);
-    }
-
-	@Test
-	public void terminateComputationalEnvironmentWhenMethodNewComputationalTerminateThrowsException() {
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
-                .thenReturn(mock(UpdateResult.class));
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-
-        String compId = "compId";
-        UserComputationalResource ucResource = new UserComputationalResource();
-        ucResource.setComputationalName(COMP_NAME);
-        ucResource.setImageName("dataengine-service");
-        ucResource.setComputationalId(compId);
-        when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString())).thenReturn(ucResource);
-
-        doThrow(new DlabException("Cannot create instance of resource 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, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, AUDIT_MESSAGE);
-        } catch (DlabException e) {
-            assertEquals("Cannot create instance of resource class ", e.getMessage());
-        }
-
-        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating, "self"));
-        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-
-        verify(requestBuilder).newComputationalTerminate(userInfo.getName(), userInstance, ucResource, endpointDTO());
-        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
-        verifyNoMoreInteractions(computationalDAO, exploratoryDAO, requestBuilder);
-    }
-
-	@Test
-	public void createDataEngineService() {
-        ProjectDTO projectDTO = getProjectDTO();
-        when(projectService.get(anyString())).thenReturn(projectDTO);
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(computationalDAO.addComputational(anyString(), anyString(), anyString(), any(UserComputationalResource.class)))
-                .thenReturn(true);
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-
-        ComputationalBase compBaseMocked = mock(ComputationalBase.class);
-        when(requestBuilder.newComputationalCreate(any(UserInfo.class), any(ProjectDTO.class),
-                any(UserInstanceDTO.class), any(ComputationalCreateFormDTO.class), any(EndpointDTO.class)))
-                .thenReturn(compBaseMocked);
-
-        when(provisioningService.post(anyString(), anyString(), any(ComputationalBase.class), any())).thenReturn(UUID);
-        when(requestId.put(anyString(), anyString())).thenReturn(UUID);
-
-        ComputationalCreateFormDTO form = formList.get(1);
-        boolean creationResult = computationalService.createDataEngineService(userInfo, form.getName(), form, ucResource, PROJECT,
-                String.format(AUDIT_MESSAGE, form.getNotebookName()));
-        assertTrue(creationResult);
-
-        verify(projectService).get(PROJECT);
-
-        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), any(ComputationalCreateFormDTO.class), refEq(endpointDTO()));
-
-        verify(provisioningService)
-                .post(endpointDTO().getUrl() + ComputationalAPI.COMPUTATIONAL_CREATE_CLOUD_SPECIFIC, TOKEN,
-                        compBaseMocked, String.class);
-
-        verify(requestId).put(USER, UUID);
-        verifyNoMoreInteractions(projectService, computationalDAO, exploratoryDAO, requestBuilder, provisioningService, requestId);
-    }
-
-	@Test
-	public void createDataEngineServiceWhenComputationalResourceNotAdded() {
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-        when(computationalDAO.addComputational(anyString(), anyString(), any(), any(UserComputationalResource.class)))
-                .thenReturn(false);
-
-        ComputationalCreateFormDTO form = formList.get(1);
-        boolean creationResult = computationalService.createDataEngineService(userInfo, form.getName(), form, ucResource, PROJECT,
-                String.format(AUDIT_MESSAGE, form.getNotebookName()));
-        assertFalse(creationResult);
-
-        verify(computationalDAO).addComputational(eq(USER), eq(EXPLORATORY_NAME), eq(PROJECT), refEq(ucResource));
-        verifyNoMoreInteractions(computationalDAO);
-    }
-
-	@Test
-	public void createDataEngineServiceWhenMethodFetchExploratoryFieldsThrowsException() {
-        when(computationalDAO.addComputational(anyString(), anyString(), anyString(), any(UserComputationalResource.class)))
-                .thenReturn(true);
-        doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
-                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
-
-        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
-                .thenReturn(mock(UpdateResult.class));
-
-        ComputationalCreateFormDTO form = formList.get(1);
-        try {
-            computationalService.createDataEngineService(userInfo, form.getName(), form, ucResource, PROJECT,
-                    String.format(AUDIT_MESSAGE, form.getNotebookName()));
-        } catch (DlabException e) {
-            assertEquals("Exploratory for user with name not found", e.getMessage());
-        }
-
-        verify(computationalDAO, never())
-                .addComputational(eq(USER), eq(EXPLORATORY_NAME), eq(PROJECT), refEq(ucResource));
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-
-        verify(computationalDAO, never()).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed,
-                "self"));
-        verifyNoMoreInteractions(computationalDAO, exploratoryDAO);
-    }
-
-	@Test
-	public void createDataEngineServiceWhenMethodNewComputationalCreateThrowsException() {
-        ProjectDTO projectDTO = getProjectDTO();
-        when(projectService.get(anyString())).thenReturn(projectDTO);
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(computationalDAO.addComputational(anyString(), anyString(), any(), any(UserComputationalResource.class)))
-                .thenReturn(true);
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-
-        doThrow(new DlabException("Cannot create instance of resource class "))
-                .when(requestBuilder).newComputationalCreate(any(UserInfo.class), any(ProjectDTO.class),
-                any(UserInstanceDTO.class), any(ComputationalCreateFormDTO.class), any(EndpointDTO.class));
-
-        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
-                .thenReturn(mock(UpdateResult.class));
-
-        ComputationalCreateFormDTO form = formList.get(1);
-        try {
-            computationalService.createDataEngineService(userInfo, form.getName(), form, ucResource, PROJECT,
-                    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());
-        }
-
-        verify(projectService).get(PROJECT);
-        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(form), refEq(endpointDTO()));
-        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
-
-        verifyNoMoreInteractions(projectService, computationalDAO, exploratoryDAO, requestBuilder);
-    }
-
-	@Test
-	public void stopSparkCluster() {
-        final UserInstanceDTO exploratory = getUserInstanceDto();
-        exploratory.setResources(singletonList(getUserComputationalResource(RUNNING, DOCKER_DLAB_DATAENGINE)));
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(exploratory);
-        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
-                .thenReturn(mock(UpdateResult.class));
-
-        ComputationalStopDTO computationalStopDTO = new ComputationalStopDTO();
-        when(requestBuilder.newComputationalStop(anyString(), any(UserInstanceDTO.class), anyString(),
-                any(EndpointDTO.class))).thenReturn(computationalStopDTO);
-        when(provisioningService.post(anyString(), anyString(), any(ComputationalBase.class), any()))
-                .thenReturn("someUuid");
-        when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
-
-        computationalService.stopSparkCluster(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, String.format(AUDIT_MESSAGE, EXPLORATORY_NAME));
-
-        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusStopping, "self"));
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, true);
-        verify(requestBuilder).newComputationalStop(eq(userInfo.getName()), refEq(exploratory), eq(COMP_NAME), refEq(endpointDTO()));
-        verify(provisioningService)
-                .post(eq(endpointDTO().getUrl() + "computational/stop/spark"), eq(TOKEN), refEq(computationalStopDTO),
-                        eq(String.class));
-        verify(requestId).put(USER, "someUuid");
-        verifyNoMoreInteractions(computationalDAO, exploratoryDAO, requestBuilder,
-                provisioningService, requestId);
-    }
-
-	@Test
-	public void stopSparkClusterWhenDataengineTypeIsAnother() {
-        final UserInstanceDTO exploratory = getUserInstanceDto();
-        exploratory.setResources(singletonList(getUserComputationalResource(RUNNING, DOCKER_DLAB_DATAENGINE_SERVICE)));
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(exploratory);
-        expectedException.expect(IllegalStateException.class);
-        expectedException.expectMessage("There is no running dataengine compName for exploratory expName");
-
-        computationalService.stopSparkCluster(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, String.format(AUDIT_MESSAGE, EXPLORATORY_NAME));
-    }
-
-	@Test
-	public void startSparkCluster() {
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        final UserInstanceDTO exploratory = getUserInstanceDto();
-        exploratory.setResources(singletonList(getUserComputationalResource(STOPPED, DOCKER_DLAB_DATAENGINE)));
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(exploratory);
-        when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
-                .thenReturn(mock(UpdateResult.class));
-
-        ComputationalStartDTO computationalStartDTO = new ComputationalStartDTO();
-        when(requestBuilder.newComputationalStart(any(UserInfo.class), any(UserInstanceDTO.class), anyString(),
-                any(EndpointDTO.class))).thenReturn(computationalStartDTO);
-        when(provisioningService.post(anyString(), anyString(), any(ComputationalBase.class), any()))
-                .thenReturn("someUuid");
-        when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
-
-        computationalService.startSparkCluster(userInfo, EXPLORATORY_NAME, COMP_NAME, PROJECT, String.format(AUDIT_MESSAGE, EXPLORATORY_NAME));
-
-        verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusStarting, "self"));
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, true);
-        verify(requestBuilder).newComputationalStart(refEq(userInfo), refEq(exploratory), eq(COMP_NAME), refEq(endpointDTO()));
-        verify(provisioningService)
-                .post(eq(endpointDTO().getUrl() + "computational/start/spark"), eq(TOKEN),
-                        refEq(computationalStartDTO),
-                        eq(String.class));
-        verify(requestId).put(USER, "someUuid");
-        verifyNoMoreInteractions(computationalDAO, exploratoryDAO, requestBuilder,
-                provisioningService, requestId);
-    }
-
-	@Test
-	public void startSparkClusterWhenDataengineStatusIsRunning() {
-        final UserInstanceDTO userInstanceDto = getUserInstanceDto();
-        userInstanceDto.setResources(singletonList(getUserComputationalResource(RUNNING,
-                DOCKER_DLAB_DATAENGINE_SERVICE)));
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(userInstanceDto);
-
-        expectedException.expect(IllegalStateException.class);
-        expectedException.expectMessage("There is no stopped dataengine compName for exploratory expName");
-
-        computationalService.startSparkCluster(userInfo, EXPLORATORY_NAME, COMP_NAME, PROJECT, String.format(AUDIT_MESSAGE, EXPLORATORY_NAME));
-    }
-
-	@Test
-	public void getComputationalResource() {
-        when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString())).thenReturn(ucResource);
-
-        Optional<UserComputationalResource> expectedResource = Optional.of(ucResource);
-        Optional<UserComputationalResource> actualResource =
-                computationalService.getComputationalResource(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
-        assertEquals(expectedResource, actualResource);
-
-        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
-        verifyNoMoreInteractions(computationalDAO);
-    }
-
-	@Test
-	public void getComputationalResourceWithException() {
-        doThrow(new DlabException("Computational resource not found"))
-                .when(computationalDAO).fetchComputationalFields(anyString(), anyString(), anyString(), anyString());
-
-        Optional<UserComputationalResource> expectedResource = Optional.empty();
-        Optional<UserComputationalResource> actualResource =
-                computationalService.getComputationalResource(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
-        assertEquals(expectedResource, actualResource);
-
-        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
-        verifyNoMoreInteractions(computationalDAO);
-    }
-
-	@Test
-	public void testUpdateSparkClusterConfig() {
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        final ComputationalClusterConfigDTO clusterConfigDTO = new ComputationalClusterConfigDTO();
-        final UserInstanceDTO userInstanceDto = getUserInstanceDto();
-        final List<ClusterConfig> config = Collections.singletonList(new ClusterConfig());
-        userInstanceDto.setResources(Collections.singletonList(getUserComputationalResource(RUNNING, COMP_NAME)));
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(userInstanceDto);
-        when(requestBuilder.newClusterConfigUpdate(any(UserInfo.class), any(UserInstanceDTO.class),
-                any(UserComputationalResource.class), anyListOf(ClusterConfig.class), any(EndpointDTO.class)))
-                .thenReturn(clusterConfigDTO);
-        when(provisioningService.post(anyString(), anyString(), any(ComputationalClusterConfigDTO.class), any()))
-                .thenReturn("someUuid");
-        computationalService.updateSparkClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME,
-                COMP_NAME, config, String.format(AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE, COMP_NAME, NOTE_BOOK_NAME));
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, true);
-        verify(requestBuilder).newClusterConfigUpdate(refEq(getUserInfo()), refEq(userInstanceDto),
-                refEq(getUserComputationalResource(RUNNING, COMP_NAME)),
-                eq(Collections.singletonList(new ClusterConfig())), eq(endpointDTO()));
-        verify(requestId).put(USER, "someUuid");
-        verify(computationalDAO).updateComputationalFields(refEq(new ComputationalStatusDTO()
-                .withProject(PROJECT)
-                .withConfig(config)
-                .withUser(USER)
-                .withExploratoryName(EXPLORATORY_NAME)
-                .withComputationalName(COMP_NAME)
-                .withStatus(UserInstanceStatus.RECONFIGURING.toString()), "self"));
-        verify(provisioningService).post(eq(endpointDTO().getUrl() + "computational/spark/reconfigure"),
-                eq(getUserInfo().getAccessToken()),
-                refEq(new ComputationalClusterConfigDTO()), eq(String.class));
-
-    }
-
-	@Test
-	public void testUpdateSparkClusterConfigWhenClusterIsNotRunning() {
-        final UserInstanceDTO userInstanceDto = getUserInstanceDto();
-        final List<ClusterConfig> config = Collections.singletonList(new ClusterConfig());
-        userInstanceDto.setResources(Collections.singletonList(getUserComputationalResource(STOPPED, COMP_NAME)));
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(userInstanceDto);
-        try {
-            computationalService.updateSparkClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME,
-                    COMP_NAME, config, String.format(AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE, COMP_NAME, NOTE_BOOK_NAME));
-        } catch (ResourceNotFoundException e) {
-            assertEquals("Running computational resource with name compName for exploratory expName not found", e.getMessage());
-        }
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, true);
-        verifyNoMoreInteractions(exploratoryDAO);
-        verifyZeroInteractions(provisioningService, requestBuilder, requestId);
-
-    }
-
-	@Test
-	public void testUpdateSparkClusterConfigWhenClusterIsNotFound() {
-        final UserInstanceDTO userInstanceDto = getUserInstanceDto();
-        final List<ClusterConfig> config = Collections.singletonList(new ClusterConfig());
-        userInstanceDto.setResources(Collections.singletonList(getUserComputationalResource(STOPPED, COMP_NAME)));
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(userInstanceDto);
-        try {
-            computationalService.updateSparkClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME,
-                    COMP_NAME + "X", config, String.format(AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE, COMP_NAME, NOTE_BOOK_NAME));
-        } catch (ResourceNotFoundException e) {
-            assertEquals("Running computational resource with name compNameX for exploratory expName not found",
-                    e.getMessage());
-        }
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, true);
-        verifyNoMoreInteractions(exploratoryDAO);
-        verifyZeroInteractions(provisioningService, requestBuilder, requestId);
-
-    }
-
-	@Test
-	public void testGetClusterConfig() {
-        when(computationalDAO.getClusterConfig(anyString(), anyString(), anyString(), anyString())).thenReturn(Collections.singletonList(getClusterConfig()));
-
-        final List<ClusterConfig> clusterConfig = computationalService.getClusterConfig(getUserInfo(), PROJECT,
-                EXPLORATORY_NAME, COMP_NAME);
-        final ClusterConfig config = clusterConfig.get(0);
-
-        assertEquals(1, clusterConfig.size());
-        assertEquals("test", config.getClassification());
-        assertNull(config.getConfigurations());
-        assertNull(config.getProperties());
-    }
-
-
-	@Test
-	public void testGetClusterConfigWithException() {
-        when(computationalDAO.getClusterConfig(anyString(), anyString(), anyString(), anyString())).thenThrow(new RuntimeException(
-                "Exception"));
-
-        expectedException.expectMessage("Exception");
-        expectedException.expect(RuntimeException.class);
-        computationalService.getClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME, COMP_NAME);
-    }
-
-	private ClusterConfig getClusterConfig() {
-		final ClusterConfig config = new ClusterConfig();
-		config.setClassification("test");
-		return config;
-	}
-
-	private UserInfo getUserInfo() {
-		return new UserInfo(USER, TOKEN);
-	}
-
-	private UserInstanceDTO getUserInstanceDto() {
-		return new UserInstanceDTO().withUser(USER).withExploratoryName(EXPLORATORY_NAME)
-                .withExploratoryId("explId")
-                .withProject(PROJECT)
-				.withTags(Collections.emptyMap());
-	}
-
-	private List<ComputationalCreateFormDTO> getFormList() {
-        SparkStandaloneClusterCreateForm sparkClusterForm = new SparkStandaloneClusterCreateForm();
-        sparkClusterForm.setNotebookName(EXPLORATORY_NAME);
-        sparkClusterForm.setName(COMP_NAME);
-        sparkClusterForm.setProject(PROJECT);
-        sparkClusterForm.setDataEngineInstanceCount(String.valueOf(2));
-        sparkClusterForm.setImage("dataengine");
-        ComputationalCreateFormDTO desClusterForm = new ComputationalCreateFormDTO();
-        desClusterForm.setNotebookName(EXPLORATORY_NAME);
-        desClusterForm.setName(COMP_NAME);
-
-        return Arrays.asList(sparkClusterForm, desClusterForm);
-    }
-
-	private ComputationalStatusDTO getComputationalStatusDTOWithStatus(String status) {
-		return new ComputationalStatusDTO()
-                .withUser(USER)
-                .withProject(PROJECT)
-				.withExploratoryName(EXPLORATORY_NAME)
-				.withComputationalName(COMP_NAME)
-				.withStatus(UserInstanceStatus.of(status));
-	}
-
-	private SparkStandaloneClusterResource getSparkClusterResource() {
-		return SparkStandaloneClusterResource.builder()
-				.computationalName(COMP_NAME)
-				.imageName("dataengine")
-				.status(CREATING.toString())
-				.dataEngineInstanceCount(String.valueOf(2))
-				.tags(Collections.emptyMap())
-				.build();
-	}
-
-	private EndpointDTO endpointDTO() {
-		return new EndpointDTO("test", "url", "", null, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
-	}
-
-
-	private UserComputationalResource getUserComputationalResource(UserInstanceStatus status, String imageName) {
-		UserComputationalResource ucResource = new UserComputationalResource();
-		ucResource.setComputationalName(COMP_NAME);
-		ucResource.setImageName("dataengine");
-		ucResource.setImageName(imageName);
-		ucResource.setStatus(status.toString());
-		ucResource.setLastActivity(LAST_ACTIVITY);
-		ucResource.setComputationalId(COMP_ID);
-		ucResource.setTags(Collections.emptyMap());
-		final SchedulerJobDTO schedulerData = new SchedulerJobDTO();
-		schedulerData.setCheckInactivityRequired(true);
-		schedulerData.setMaxInactivity(MAX_INACTIVITY);
-		ucResource.setSchedulerData(schedulerData);
-		return ucResource;
-	}
-
-	private ProjectDTO getProjectDTO() {
-        return new ProjectDTO(PROJECT, Collections.emptySet(), "", "", null,
-                singletonList(new ProjectEndpointDTO("endpoint", UserInstanceStatus.RUNNING,
-                        new EdgeInfo())), true);
-    }
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/EndpointServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/EndpointServiceImplTest.java
deleted file mode 100644
index 6bf3f73..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/EndpointServiceImplTest.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * 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.EndpointDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.UserRoleDAO;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.EndpointResourcesDTO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.domain.ProjectEndpointDTO;
-import com.epam.dlab.backendapi.resources.TestBase;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceConflictException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.rest.client.RESTService;
-import org.apache.http.HttpStatus;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import javax.ws.rs.core.Response;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyListOf;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class EndpointServiceImplTest extends TestBase {
-	private static final String HEALTH_CHECK = "healthcheck";
-	private static final String EXPLORATORY_NAME_1 = "expName1";
-	private static final String EXPLORATORY_NAME_2 = "expName2";
-	private static final String PROJECT_NAME_1 = "projectName";
-	private static final String PROJECT_NAME_2 = "projectName_2";
-
-	@Mock
-	private EndpointDAO endpointDAO;
-	@Mock
-	private ProjectService projectService;
-	@Mock
-	private ExploratoryDAO exploratoryDAO;
-	@Mock
-	private RESTService provisioningService;
-	@Mock
-	private UserRoleDAO userRoleDao;
-
-	@InjectMocks
-	private EndpointServiceImpl endpointService;
-
-	@Test
-	public void getEndpoints() {
-		List<EndpointDTO> endpoints = getEndpointDTOs();
-		when(endpointDAO.getEndpoints()).thenReturn(endpoints);
-
-		List<EndpointDTO> actualEndpoints = endpointService.getEndpoints();
-
-		assertEquals("lists should be equal", endpoints, actualEndpoints);
-		verify(endpointDAO).getEndpoints();
-		verifyNoMoreInteractions(endpointDAO);
-	}
-
-	@Test
-	public void getEndpointsWithStatus() {
-		List<EndpointDTO> endpoints = Collections.singletonList(getEndpointDTO());
-		when(endpointDAO.getEndpointsWithStatus(anyString())).thenReturn(endpoints);
-
-		List<EndpointDTO> actualEndpoints = endpointService.getEndpointsWithStatus(EndpointDTO.EndpointStatus.ACTIVE);
-
-		assertEquals("lists should be equal", endpoints, actualEndpoints);
-		verify(endpointDAO).getEndpointsWithStatus(EndpointDTO.EndpointStatus.ACTIVE.toString());
-		verifyNoMoreInteractions(endpointDAO);
-	}
-
-	@Test
-	public void getEndpointResources() {
-		List<UserInstanceDTO> userInstances = getUserInstances();
-		List<ProjectDTO> projectDTOs = getProjectDTOs();
-		when(exploratoryDAO.fetchExploratoriesByEndpointWhereStatusNotIn(anyString(), anyListOf(UserInstanceStatus.class)))
-				.thenReturn(userInstances);
-		when(projectService.getProjectsByEndpoint(anyString())).thenReturn(projectDTOs);
-
-		EndpointResourcesDTO actualEndpointResources = endpointService.getEndpointResources(ENDPOINT_NAME);
-
-		assertEquals("objects should be equal", new EndpointResourcesDTO(userInstances, projectDTOs), actualEndpointResources);
-		verify(exploratoryDAO).fetchExploratoriesByEndpointWhereStatusNotIn(ENDPOINT_NAME, Arrays.asList(UserInstanceStatus.TERMINATED, UserInstanceStatus.FAILED));
-		verify(projectService).getProjectsByEndpoint(ENDPOINT_NAME);
-		verifyNoMoreInteractions(exploratoryDAO, projectService);
-	}
-
-	@Test
-	public void get() {
-		EndpointDTO endpointDTO = getEndpointDTO();
-		when(endpointDAO.get(anyString())).thenReturn(Optional.of(endpointDTO));
-
-		EndpointDTO actualEndpointDTO = endpointService.get(ENDPOINT_NAME);
-
-		assertEquals("objects should be equal", endpointDTO, actualEndpointDTO);
-		verify(endpointDAO).get(ENDPOINT_NAME);
-		verifyNoMoreInteractions(endpointDAO);
-	}
-
-	@Test(expected = ResourceNotFoundException.class)
-	public void getWithException() {
-		when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
-
-		endpointService.get(ENDPOINT_NAME);
-	}
-
-	@Test
-	public void create() {
-		Response response = mock(Response.class);
-		when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
-		when(endpointDAO.getEndpointWithUrl(anyString())).thenReturn(Optional.empty());
-		when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(response);
-		when(response.readEntity(any(Class.class))).thenReturn(CloudProvider.AWS);
-		when(response.getStatus()).thenReturn(HttpStatus.SC_OK);
-
-		endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
-
-		verify(endpointDAO).get(ENDPOINT_NAME);
-		verify(endpointDAO).getEndpointWithUrl(ENDPOINT_URL);
-		verify(provisioningService).get(ENDPOINT_URL + HEALTH_CHECK, TOKEN, Response.class);
-		verify(endpointDAO).create(getEndpointDTO());
-		verify(userRoleDao).updateMissingRoles(CloudProvider.AWS);
-		verifyNoMoreInteractions(endpointDAO, provisioningService, userRoleDao);
-	}
-
-	@Test(expected = ResourceConflictException.class)
-	public void createWithException1() {
-		when(endpointDAO.get(anyString())).thenReturn(Optional.of(getEndpointDTO()));
-
-		endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
-	}
-
-	@Test(expected = ResourceConflictException.class)
-	public void createWithException2() {
-		when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
-		when(endpointDAO.getEndpointWithUrl(anyString())).thenReturn(Optional.of(getEndpointDTO()));
-
-		endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
-	}
-
-	@Test(expected = DlabException.class)
-	public void createWithException3() {
-		when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
-		when(endpointDAO.getEndpointWithUrl(anyString())).thenReturn(Optional.empty());
-		when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenThrow(new DlabException("Exception message"));
-
-		endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
-	}
-
-	@Test(expected = DlabException.class)
-	public void createWithException4() {
-		Response response = mock(Response.class);
-		when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
-		when(endpointDAO.getEndpointWithUrl(anyString())).thenReturn(Optional.empty());
-		when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(response);
-		when(response.readEntity(any(Class.class))).thenReturn(new Object());
-
-		endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
-	}
-
-	@Test(expected = ResourceNotFoundException.class)
-	public void createWithException5() {
-		Response response = mock(Response.class);
-		when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
-		when(endpointDAO.getEndpointWithUrl(anyString())).thenReturn(Optional.empty());
-		when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(response);
-		when(response.readEntity(any(Class.class))).thenReturn(CloudProvider.AWS);
-		when(response.getStatus()).thenReturn(HttpStatus.SC_INTERNAL_SERVER_ERROR);
-
-		endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
-	}
-
-	@Test(expected = DlabException.class)
-	public void createWithException6() {
-		Response response = mock(Response.class);
-		when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
-		when(endpointDAO.getEndpointWithUrl(anyString())).thenReturn(Optional.empty());
-		when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(response);
-		when(response.readEntity(any(Class.class))).thenReturn(null);
-		when(response.getStatus()).thenReturn(HttpStatus.SC_OK);
-
-		endpointService.create(getUserInfo(), ENDPOINT_NAME, getEndpointDTO());
-	}
-
-	@Test
-	public void updateEndpointStatus() {
-		endpointService.updateEndpointStatus(ENDPOINT_NAME, EndpointDTO.EndpointStatus.ACTIVE);
-
-		verify(endpointDAO).updateEndpointStatus(ENDPOINT_NAME, EndpointDTO.EndpointStatus.ACTIVE.toString());
-		verifyNoMoreInteractions(endpointDAO);
-	}
-
-	@Test
-	public void remove() {
-		List<ProjectDTO> projectDTOs = getProjectDTOs();
-		List<EndpointDTO> endpointDTOs = getEndpointDTOs();
-		when(endpointDAO.get(anyString())).thenReturn(Optional.of(getEndpointDTO()));
-		when(projectService.getProjectsByEndpoint(anyString())).thenReturn(projectDTOs);
-		when(projectService.checkExploratoriesAndComputationalProgress(anyString(), anyListOf(String.class))).thenReturn(Boolean.TRUE);
-		when(endpointDAO.getEndpoints()).thenReturn(endpointDTOs);
-
-		endpointService.remove(getUserInfo(), ENDPOINT_NAME);
-
-		verify(endpointDAO).get(ENDPOINT_NAME);
-		verify(projectService).getProjectsByEndpoint(ENDPOINT_NAME);
-		verify(projectService).checkExploratoriesAndComputationalProgress(PROJECT_NAME_1, Collections.singletonList(ENDPOINT_NAME));
-		verify(projectService).checkExploratoriesAndComputationalProgress(PROJECT_NAME_2, Collections.singletonList(ENDPOINT_NAME));
-		verify(projectService).terminateEndpoint(getUserInfo(), ENDPOINT_NAME, PROJECT_NAME_1);
-		verify(projectService).terminateEndpoint(getUserInfo(), ENDPOINT_NAME, PROJECT_NAME_2);
-		verify(endpointDAO).remove(ENDPOINT_NAME);
-		verify(endpointDAO).getEndpoints();
-		verify(userRoleDao).removeUnnecessaryRoles(CloudProvider.AWS, Arrays.asList(CloudProvider.AWS, CloudProvider.GCP));
-		verifyNoMoreInteractions(endpointDAO, projectService, userRoleDao);
-	}
-
-	@Test(expected = ResourceNotFoundException.class)
-	public void removeWithException1() {
-		when(endpointDAO.get(anyString())).thenReturn(Optional.empty());
-
-		endpointService.remove(getUserInfo(), ENDPOINT_NAME);
-	}
-
-	@Test(expected = ResourceConflictException.class)
-	public void removeWithException2() {
-		when(endpointDAO.get(anyString())).thenReturn(Optional.of(getEndpointDTO()));
-		when(projectService.getProjectsByEndpoint(anyString())).thenReturn(getProjectDTOs());
-		when(projectService.checkExploratoriesAndComputationalProgress(anyString(), anyListOf(String.class))).thenReturn(Boolean.FALSE);
-
-		endpointService.remove(getUserInfo(), ENDPOINT_NAME);
-	}
-
-	@Test(expected = ResourceConflictException.class)
-	public void removeWithException3() {
-		when(endpointDAO.get(anyString())).thenReturn(Optional.of(getEndpointDTO()));
-		when(projectService.getProjectsByEndpoint(anyString())).thenReturn(getCreatingProjectDTO());
-		when(projectService.checkExploratoriesAndComputationalProgress(anyString(), anyListOf(String.class))).thenReturn(Boolean.TRUE);
-
-		endpointService.remove(getUserInfo(), ENDPOINT_NAME);
-	}
-
-	private List<UserInstanceDTO> getUserInstances() {
-		return Arrays.asList(
-				new UserInstanceDTO().withExploratoryName(EXPLORATORY_NAME_1).withUser(USER).withProject(PROJECT_NAME_1).withEndpoint(ENDPOINT_NAME),
-				new UserInstanceDTO().withExploratoryName(EXPLORATORY_NAME_2).withUser(USER).withProject(PROJECT_NAME_1).withEndpoint(ENDPOINT_NAME)
-		);
-	}
-
-	private List<EndpointDTO> getEndpointDTOs() {
-		return Arrays.asList(getEndpointDTO(), getInactiveEndpointDTO());
-	}
-
-	private EndpointDTO getInactiveEndpointDTO() {
-		return new EndpointDTO("local2", "endpoint_url2", "endpoint_account2", "endpoint_tag2",
-				EndpointDTO.EndpointStatus.INACTIVE, CloudProvider.GCP);
-	}
-
-	private List<ProjectDTO> getProjectDTOs() {
-		ProjectDTO project1 = ProjectDTO.builder()
-				.name(PROJECT_NAME_1)
-				.endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, null)))
-				.build();
-		ProjectDTO project2 = ProjectDTO.builder()
-				.name(PROJECT_NAME_2)
-				.endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, null)))
-				.build();
-		return Arrays.asList(project1, project2);
-	}
-
-	private List<ProjectDTO> getCreatingProjectDTO() {
-		ProjectDTO project = ProjectDTO.builder()
-				.name(PROJECT_NAME_1)
-				.endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.CREATING, null)))
-				.build();
-		return Collections.singletonList(project);
-	}
-}
\ No newline at end of file
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
deleted file mode 100644
index 2f2c7c7..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImplTest.java
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.EnvDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.UserSettingsDAO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.domain.ProjectEndpointDTO;
-import com.epam.dlab.backendapi.resources.dto.UserDTO;
-import com.epam.dlab.backendapi.resources.dto.UserResourceInfo;
-import com.epam.dlab.backendapi.service.ComputationalService;
-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.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.edge.EdgeInfo;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceConflictException;
-import com.epam.dlab.model.ResourceEnum;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-import static com.epam.dlab.dto.UserInstanceStatus.CREATING;
-import static com.epam.dlab.dto.UserInstanceStatus.CREATING_IMAGE;
-import static com.epam.dlab.dto.UserInstanceStatus.STARTING;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.anyListOf;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anySet;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-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 DLAB_SYSTEM_USER_TOKEN = "token";
-	private static final String USER = "test";
-	private static final String EXPLORATORY_NAME_1 = "expName1";
-	private static final String EXPLORATORY_NAME_2 = "expName2";
-	private static final String TOKEN = "token";
-	private static final String UUID = "213-12312-321";
-	private static final String PROJECT_NAME = "projectName";
-	private static final String ENDPOINT_NAME = "endpointName";
-	private static final String SHAPE = "shape";
-
-	@Mock
-	private EnvDAO envDAO;
-	@Mock
-	private ExploratoryDAO exploratoryDAO;
-	@Mock
-	private SecurityService securityService;
-	@Mock
-	private ExploratoryService exploratoryService;
-	@Mock
-	private ComputationalService computationalService;
-	@Mock
-	private UserSettingsDAO userSettingsDAO;
-	@Mock
-	private ProjectService projectService;
-
-	@InjectMocks
-	private EnvironmentServiceImpl environmentService;
-
-	@Rule
-	public ExpectedException expectedException = ExpectedException.none();
-
-	@Test
-	public void getActiveUsers() {
-		doReturn(Collections.singleton(USER)).when(envDAO).fetchActiveEnvUsers();
-		doReturn(Collections.singleton(USER + "2")).when(envDAO).fetchUsersNotIn(anySet());
-		when(userSettingsDAO.getAllowedBudget(anyString())).thenReturn(Optional.empty());
-		final List<UserDTO> activeUsers = environmentService.getUsers();
-
-		assertEquals(2, activeUsers.size());
-		assertEquals(USER, activeUsers.get(0).getName());
-		assertEquals(USER + "2", activeUsers.get(1).getName());
-
-		verify(userSettingsDAO).getAllowedBudget(USER);
-		verify(userSettingsDAO).getAllowedBudget(USER + "2");
-		verify(envDAO).fetchActiveEnvUsers();
-		verify(envDAO).fetchUsersNotIn(Collections.singleton(USER));
-		verifyNoMoreInteractions(envDAO);
-	}
-
-	@Test
-	public void getAllEnv() {
-		when(exploratoryDAO.getInstances()).thenReturn(getUserInstances());
-		when(projectService.getProjects(any(UserInfo.class))).thenReturn(Collections.singletonList(getProjectDTO()));
-
-		List<UserResourceInfo> actualAllEnv = environmentService.getAllEnv(getUserInfo());
-
-		List<UserResourceInfo> userResources = Arrays.asList(getUserResourceInfoEdge(), getUserResourceInfo(EXPLORATORY_NAME_1), getUserResourceInfo(EXPLORATORY_NAME_2));
-		assertEquals("lists are not equal", userResources, actualAllEnv);
-		verify(exploratoryDAO).getInstances();
-		verify(projectService).getProjects(getUserInfo());
-		verifyNoMoreInteractions(exploratoryDAO, projectService);
-	}
-
-	@Test
-	public void getAllEnvWithoutEdge() {
-		when(exploratoryDAO.getInstances()).thenReturn(getUserInstances());
-		when(projectService.getProjects(any(UserInfo.class))).thenReturn(Collections.singletonList(getProjectDTOWithoutEndpoint()));
-
-		List<UserResourceInfo> actualAllEnv = environmentService.getAllEnv(getUserInfo());
-
-		List<UserResourceInfo> userResources = Arrays.asList(getUserResourceInfo(EXPLORATORY_NAME_1), getUserResourceInfo(EXPLORATORY_NAME_2));
-		assertEquals("lists are not equal", userResources, actualAllEnv);
-		verify(exploratoryDAO).getInstances();
-		verify(projectService).getProjects(getUserInfo());
-		verifyNoMoreInteractions(exploratoryDAO, projectService);
-	}
-
-	@Test
-	public void stopAll() {
-		when(projectService.getProjects()).thenReturn(Collections.singletonList(getProjectDTO()));
-		when(exploratoryDAO.fetchProjectExploratoriesWhereStatusIn(anyString(), anyListOf(UserInstanceStatus.class))).thenReturn(Collections.emptyList());
-		when(exploratoryDAO.fetchRunningExploratoryFieldsForProject(anyString())).thenReturn(getUserInstances());
-		when(securityService.getServiceAccountInfo(anyString())).thenReturn(getDLabSystemUser());
-		when(projectService.get(anyString())).thenReturn(getProjectDTO());
-
-		environmentService.stopAll();
-
-		verify(projectService).getProjects();
-		verify(exploratoryDAO).fetchProjectExploratoriesWhereStatusIn(PROJECT_NAME, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE);
-		verify(exploratoryDAO).fetchRunningExploratoryFieldsForProject(PROJECT_NAME);
-		verify(securityService, times(3)).getServiceAccountInfo(DLAB_SYSTEM_USER);
-		verify(exploratoryService).stop(getDLabSystemUser(), USER, PROJECT_NAME, EXPLORATORY_NAME_1, AUDIT_QUOTA_MESSAGE);
-		verify(exploratoryService).stop(getDLabSystemUser(), USER, PROJECT_NAME, EXPLORATORY_NAME_2, AUDIT_QUOTA_MESSAGE);
-		verify(projectService).get(PROJECT_NAME);
-		verify(projectService).stop(getDLabSystemUser(), ENDPOINT_NAME, PROJECT_NAME, AUDIT_QUOTA_MESSAGE);
-		verifyNoMoreInteractions(projectService, exploratoryDAO, securityService, exploratoryService);
-	}
-
-	@Test(expected = ResourceConflictException.class)
-	public void stopAllWithException() {
-		when(projectService.getProjects()).thenReturn(Collections.singletonList(getProjectDTO()));
-		when(exploratoryDAO.fetchProjectExploratoriesWhereStatusIn(PROJECT_NAME, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE)).thenReturn(getUserInstances());
-
-		environmentService.stopAll();
-
-		verify(projectService).getProjects();
-		verify(exploratoryDAO).fetchProjectExploratoriesWhereStatusIn(PROJECT_NAME, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE);
-		verifyNoMoreInteractions(projectService, exploratoryDAO, securityService, exploratoryService);
-	}
-
-	@Test
-	public void stopAllWithStoppedProject() {
-		when(projectService.getProjects()).thenReturn(Collections.singletonList(getProjectDTOWithStoppedEdge()));
-		when(exploratoryDAO.fetchProjectExploratoriesWhereStatusIn(anyString(), anyListOf(UserInstanceStatus.class))).thenReturn(Collections.emptyList());
-		when(exploratoryDAO.fetchRunningExploratoryFieldsForProject(anyString())).thenReturn(getUserInstances());
-		when(securityService.getServiceAccountInfo(anyString())).thenReturn(getDLabSystemUser());
-		when(projectService.get(anyString())).thenReturn(getProjectDTOWithStoppedEdge());
-
-		environmentService.stopAll();
-
-		verify(projectService).getProjects();
-		verify(exploratoryDAO).fetchProjectExploratoriesWhereStatusIn(PROJECT_NAME, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE);
-		verify(exploratoryDAO).fetchRunningExploratoryFieldsForProject(PROJECT_NAME);
-		verify(securityService, times(2)).getServiceAccountInfo(DLAB_SYSTEM_USER);
-		verify(exploratoryService).stop(getDLabSystemUser(), USER, PROJECT_NAME, EXPLORATORY_NAME_1, AUDIT_QUOTA_MESSAGE);
-		verify(exploratoryService).stop(getDLabSystemUser(), USER, PROJECT_NAME, EXPLORATORY_NAME_2, AUDIT_QUOTA_MESSAGE);
-		verify(projectService).get(PROJECT_NAME);
-		verifyNoMoreInteractions(projectService, exploratoryDAO, securityService, exploratoryService);
-	}
-
-	@Test
-	public void stopEnvironmentWithServiceAccount() {
-		when(exploratoryDAO.fetchUserExploratoriesWhereStatusIn(anyString(), anyListOf(UserInstanceStatus.class))).thenReturn(Collections.emptyList());
-		when(exploratoryDAO.fetchRunningExploratoryFields(anyString())).thenReturn(getUserInstances());
-		when(securityService.getServiceAccountInfo(anyString())).thenReturn(getDLabSystemUser());
-
-		environmentService.stopEnvironmentWithServiceAccount(USER);
-
-		verify(exploratoryDAO).fetchUserExploratoriesWhereStatusIn(USER, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE);
-		verify(exploratoryDAO).fetchRunningExploratoryFields(USER);
-		verify(securityService, times(2)).getServiceAccountInfo(DLAB_SYSTEM_USER);
-		verify(exploratoryService).stop(getDLabSystemUser(), USER, PROJECT_NAME, EXPLORATORY_NAME_1, AUDIT_QUOTA_MESSAGE);
-		verify(exploratoryService).stop(getDLabSystemUser(), USER, PROJECT_NAME, EXPLORATORY_NAME_2, AUDIT_QUOTA_MESSAGE);
-		verifyNoMoreInteractions(exploratoryDAO, securityService, exploratoryService);
-	}
-
-	@Test(expected = ResourceConflictException.class)
-	public void stopEnvironmentWithServiceAccountWithException() {
-		when(exploratoryDAO.fetchUserExploratoriesWhereStatusIn(USER, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE))
-				.thenReturn(getUserInstances());
-
-		environmentService.stopEnvironmentWithServiceAccount(USER);
-
-		verify(exploratoryDAO).fetchUserExploratoriesWhereStatusIn(USER, Arrays.asList(CREATING, STARTING, CREATING_IMAGE), CREATING, STARTING, CREATING_IMAGE);
-		verifyNoMoreInteractions(exploratoryDAO, securityService, exploratoryService);
-	}
-
-	@Test
-	public void getActiveUsersWithException() {
-		doThrow(new DlabException("Users not found")).when(envDAO).fetchActiveEnvUsers();
-
-		expectedException.expect(DlabException.class);
-		expectedException.expectMessage("Users not found");
-
-		environmentService.getUsers();
-	}
-
-	@Test
-	public void stopProjectEnvironment() {
-        final UserInfo userInfo = getUserInfo();
-        final ProjectDTO projectDTO = getProjectDTO();
-        when(exploratoryDAO.fetchRunningExploratoryFieldsForProject(anyString())).thenReturn(getUserInstances());
-        when(securityService.getServiceAccountInfo(anyString())).thenReturn(userInfo);
-        when(exploratoryService.stop(any(UserInfo.class), anyString(), anyString(), anyString(), anyString())).thenReturn(UUID);
-        when(projectService.get(anyString())).thenReturn(projectDTO);
-        doNothing().when(projectService).stop(any(UserInfo.class), anyString(), anyString(), anyString());
-
-        environmentService.stopProjectEnvironment(PROJECT_NAME);
-
-        verify(exploratoryDAO).fetchRunningExploratoryFieldsForProject(PROJECT_NAME);
-        verify(exploratoryService).stop(refEq(userInfo), eq(USER), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq(AUDIT_QUOTA_MESSAGE));
-        verify(exploratoryService).stop(refEq(userInfo), eq(USER), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_2), eq(AUDIT_QUOTA_MESSAGE));
-        verify(securityService, times(3)).getServiceAccountInfo(DLAB_SYSTEM_USER);
-        verify(projectService).get(eq(PROJECT_NAME));
-        verify(projectService).stop(refEq(userInfo), eq(ENDPOINT_NAME), eq(PROJECT_NAME), eq(AUDIT_QUOTA_MESSAGE));
-        verify(exploratoryDAO).fetchProjectExploratoriesWhereStatusIn(PROJECT_NAME, Arrays.asList(UserInstanceStatus.CREATING,
-                UserInstanceStatus.STARTING, UserInstanceStatus.CREATING_IMAGE),
-                UserInstanceStatus.CREATING, UserInstanceStatus.STARTING, UserInstanceStatus.CREATING_IMAGE);
-        verifyNoMoreInteractions(exploratoryDAO, exploratoryService, projectService);
-    }
-
-	@Test
-	public void stopExploratory() {
-        final UserInfo userInfo = getUserInfo();
-        when(exploratoryService.stop(any(UserInfo.class), anyString(), anyString(), anyString(), anyString())).thenReturn(UUID);
-
-        environmentService.stopExploratory(userInfo, USER, PROJECT_NAME, EXPLORATORY_NAME_1);
-
-        verify(exploratoryService).stop(refEq(userInfo), eq(USER), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq(null));
-        verifyNoMoreInteractions(securityService, exploratoryService);
-    }
-
-	@Test
-	public void stopComputational() {
-        final UserInfo userInfo = getUserInfo();
-        doNothing().when(computationalService).stopSparkCluster(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString());
-
-        environmentService.stopComputational(userInfo, USER, PROJECT_NAME, EXPLORATORY_NAME_1, "compName");
-
-        verify(computationalService).stopSparkCluster(refEq(userInfo), eq(userInfo.getName()), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq("compName"),
-                eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME_1)));
-        verifyNoMoreInteractions(securityService, computationalService);
-    }
-
-	@Test
-	public void terminateExploratory() {
-        final UserInfo userInfo = getUserInfo();
-        when(exploratoryService.terminate(any(UserInfo.class), anyString(), anyString(), anyString(), anyString())).thenReturn(UUID);
-
-        environmentService.terminateExploratory(userInfo, USER, PROJECT_NAME, EXPLORATORY_NAME_1);
-
-        verify(exploratoryService).terminate(refEq(userInfo), eq(USER), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq(null));
-        verifyNoMoreInteractions(securityService, exploratoryService);
-    }
-
-	@Test
-	public void terminateComputational() {
-		final UserInfo userInfo = getUserInfo();
-		doNothing().when(computationalService)
-				.terminateComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString());
-
-		environmentService.terminateComputational(userInfo, USER, PROJECT_NAME, EXPLORATORY_NAME_1, "compName");
-
-		verify(computationalService).terminateComputational(refEq(userInfo), eq(userInfo.getName()), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq("compName"),
-				eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME_1)));
-		verifyNoMoreInteractions(securityService, computationalService);
-	}
-
-	private UserResourceInfo getUserResourceInfoEdge() {
-		return UserResourceInfo.builder()
-				.resourceType(ResourceEnum.EDGE_NODE)
-				.resourceStatus("running")
-				.project(PROJECT_NAME)
-				.endpoint(ENDPOINT_NAME)
-				.ip(null)
-				.build();
-	}
-
-	private UserResourceInfo getUserResourceInfo(String exploratoryName) {
-		return UserResourceInfo.builder()
-				.resourceType(ResourceEnum.NOTEBOOK)
-				.resourceName(exploratoryName)
-				.resourceShape(SHAPE)
-				.resourceStatus("running")
-				.computationalResources(Collections.emptyList())
-				.user(USER)
-				.project(PROJECT_NAME)
-				.endpoint(ENDPOINT_NAME)
-				.cloudProvider("aws")
-				.exploratoryUrls(null)
-				.build();
-	}
-
-	private UserInfo getUserInfo() {
-		return new UserInfo(USER, TOKEN);
-	}
-
-	private UserInfo getDLabSystemUser() {
-		return new UserInfo(DLAB_SYSTEM_USER, DLAB_SYSTEM_USER_TOKEN);
-	}
-
-	private List<UserInstanceDTO> getUserInstances() {
-		return Arrays.asList(
-				new UserInstanceDTO().withExploratoryName(EXPLORATORY_NAME_1).withUser(USER).withProject(PROJECT_NAME).withEndpoint(ENDPOINT_NAME)
-						.withShape(SHAPE).withStatus("running").withResources(Collections.emptyList()).withCloudProvider("aws"),
-				new UserInstanceDTO().withExploratoryName(EXPLORATORY_NAME_2).withUser(USER).withProject(PROJECT_NAME).withEndpoint(ENDPOINT_NAME)
-						.withShape(SHAPE).withStatus("running").withResources(Collections.emptyList()).withCloudProvider("aws"));
-	}
-
-	private ProjectDTO getProjectDTO() {
-		return new ProjectDTO(PROJECT_NAME, Collections.emptySet(), "", "", null,
-				Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, new EdgeInfo())), true);
-	}
-
-	private ProjectDTO getProjectDTOWithStoppedEdge() {
-		return new ProjectDTO(PROJECT_NAME, Collections.emptySet(), "", "", null,
-				Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.STOPPED, new EdgeInfo())), true);
-	}
-
-	private ProjectDTO getProjectDTOWithoutEndpoint() {
-		return new ProjectDTO(PROJECT_NAME, Collections.emptySet(), "", "", null, null, true);
-	}
-}
\ No newline at end of file
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
deleted file mode 100644
index a4412af..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImplTest.java
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.ComputationalDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.GitCredsDAO;
-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.service.EndpointService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.backendapi.service.TagService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.cloud.CloudProvider;
-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.base.edge.EdgeInfo;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.dto.exploratory.ExploratoryActionDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryCreateDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryStatusDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.model.exploratory.Exploratory;
-import com.epam.dlab.rest.client.RESTService;
-import com.mongodb.client.result.UpdateResult;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-import static java.util.Collections.singletonList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyListOf;
-import static org.mockito.Mockito.anyMapOf;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.anyVararg;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class ExploratoryServiceImplTest {
-
-    private final String USER = "test";
-    private final String TOKEN = "token";
-    private final String PROJECT = "project";
-    private final String EXPLORATORY_NAME = "expName";
-    private final String UUID = "1234-56789765-4321";
-    private static final String ENDPOINT_NAME = "endpointName";
-
-
-    private UserInfo userInfo;
-    private UserInstanceDTO userInstance;
-    private StatusEnvBaseDTO statusEnvBaseDTO;
-
-    @Mock
-    private ProjectService projectService;
-    @Mock
-    private ExploratoryDAO exploratoryDAO;
-    @Mock
-    private ComputationalDAO computationalDAO;
-    @Mock
-    private GitCredsDAO gitCredsDAO;
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-    @Mock
-    private RESTService provisioningService;
-    @Mock
-    private RequestBuilder requestBuilder;
-    @Mock
-    private RequestId requestId;
-    @Mock
-    private TagService tagService;
-    @Mock
-    private EndpointService endpointService;
-    @Mock
-    private SelfServiceApplicationConfiguration configuration;
-    @InjectMocks
-    private ExploratoryServiceImpl exploratoryService;
-
-    @Before
-    public void setUp() {
-        when(configuration.isAuditEnabled()).thenReturn(false);
-        userInfo = getUserInfo();
-        userInstance = getUserInstanceDto();
-    }
-
-    @Test
-    public void start() {
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-
-        ExploratoryGitCredsDTO egcDtoMock = mock(ExploratoryGitCredsDTO.class);
-        when(gitCredsDAO.findGitCreds(anyString())).thenReturn(egcDtoMock);
-
-        ExploratoryActionDTO egcuDto = new ExploratoryGitCredsUpdateDTO();
-        egcuDto.withExploratoryName(EXPLORATORY_NAME);
-        when(requestBuilder.newExploratoryStart(any(UserInfo.class), any(UserInstanceDTO.class), any(EndpointDTO.class),
-                any(ExploratoryGitCredsDTO.class))).thenReturn(egcuDto);
-
-        String exploratoryStart = "exploratory/start";
-        when(provisioningService.post(anyString(), anyString(), any(ExploratoryActionDTO.class), any()))
-                .thenReturn(UUID);
-        when(requestId.put(anyString(), anyString())).thenReturn(UUID);
-
-        String uuid = exploratoryService.start(userInfo, EXPLORATORY_NAME, "project", null);
-        assertNotNull(uuid);
-        assertEquals(UUID, uuid);
-
-        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("starting");
-
-        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(provisioningService).post(endpointDTO().getUrl() + exploratoryStart, TOKEN, egcuDto, String.class);
-        verify(requestId).put(USER, UUID);
-        verifyNoMoreInteractions(exploratoryDAO, provisioningService, requestId);
-    }
-
-	@Test
-	public void startWhenMethodFetchExploratoryFieldsThrowsException() {
-        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
-        doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
-                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
-        try {
-            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());
-        }
-        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("starting");
-        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-
-        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("failed");
-        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
-        verifyNoMoreInteractions(exploratoryDAO);
-    }
-
-	@Test
-	public void stop() {
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
-        when(computationalDAO.updateComputationalStatusesForExploratory(any(StatusEnvBaseDTO.class))).thenReturn(1);
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-
-        ExploratoryActionDTO eaDto = new ExploratoryActionDTO();
-        eaDto.withExploratoryName(EXPLORATORY_NAME);
-        when(requestBuilder.newExploratoryStop(anyString(), any(UserInstanceDTO.class), any(EndpointDTO.class)))
-                .thenReturn(eaDto);
-
-        String exploratoryStop = "exploratory/stop";
-        when(provisioningService.post(anyString(), anyString(), any(ExploratoryActionDTO.class), any())).thenReturn
-                (UUID);
-        when(requestId.put(anyString(), anyString())).thenReturn(UUID);
-
-        String uuid = exploratoryService.stop(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, null);
-        assertNotNull(uuid);
-        assertEquals(UUID, uuid);
-
-        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("stopping");
-
-        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(provisioningService).post(endpointDTO().getUrl() + exploratoryStop, TOKEN, eaDto, String.class);
-        verify(computationalDAO).updateComputationalStatusesForExploratory(userInfo.getName(), PROJECT,
-                EXPLORATORY_NAME, UserInstanceStatus.STOPPING, UserInstanceStatus.TERMINATING,
-                UserInstanceStatus.FAILED, UserInstanceStatus.TERMINATED, UserInstanceStatus.STOPPED);
-        verify(requestId).put(USER, UUID);
-        verifyNoMoreInteractions(exploratoryDAO, provisioningService, requestId);
-    }
-
-	@Test
-	public void stopWhenMethodFetchExploratoryFieldsThrowsException() {
-        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
-        doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
-                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
-        try {
-            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());
-        }
-        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("stopping");
-        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-
-        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("failed");
-        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
-        verifyNoMoreInteractions(exploratoryDAO);
-    }
-
-	@Test
-	public void terminate() {
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
-        when(computationalDAO.updateComputationalStatusesForExploratory(any(StatusEnvBaseDTO.class))).thenReturn(1);
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-
-        ExploratoryActionDTO eaDto = new ExploratoryActionDTO();
-        eaDto.withExploratoryName(EXPLORATORY_NAME);
-        when(requestBuilder.newExploratoryStop(anyString(), any(UserInstanceDTO.class), any(EndpointDTO.class)))
-                .thenReturn(eaDto);
-
-        String exploratoryTerminate = "exploratory/terminate";
-        when(provisioningService.post(anyString(), anyString(), any(ExploratoryActionDTO.class), any())).thenReturn
-                (UUID);
-        when(requestId.put(anyString(), anyString())).thenReturn(UUID);
-
-        String uuid = exploratoryService.terminate(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, null);
-        assertNotNull(uuid);
-        assertEquals(UUID, uuid);
-
-        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("terminating");
-
-        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(computationalDAO).updateComputationalStatusesForExploratory(USER, PROJECT, EXPLORATORY_NAME,
-                UserInstanceStatus.TERMINATING, UserInstanceStatus.TERMINATING, UserInstanceStatus.TERMINATED,
-                UserInstanceStatus.FAILED);
-        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);
-    }
-
-	@Test
-	public void terminateWhenMethodFetchExploratoryFieldsThrowsException() {
-        when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
-        doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
-                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
-        try {
-            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());
-        }
-        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("terminating");
-        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-
-        statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("failed");
-        verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
-        verifyNoMoreInteractions(exploratoryDAO);
-    }
-
-	@Test
-	public void create() {
-		ProjectDTO projectDTO = getProjectDTO();
-		when(projectService.get(anyString())).thenReturn(projectDTO);
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-		doNothing().when(exploratoryDAO).insertExploratory(any(UserInstanceDTO.class));
-		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);
-
-        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);
-		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", "exploratory");
-        verify(endpointService).get(anyString());
-    }
-
-	@Test
-	public void createWhenMethodInsertExploratoryThrowsExceptionWithItsCatching() {
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-		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", "exploratory");
-        } catch (DlabException e) {
-			assertEquals("Could not create exploratory environment expName for user test: null",
-					e.getMessage());
-		}
-		userInstance.withStatus("creating");
-		userInstance.withResources(Collections.emptyList());
-		verify(exploratoryDAO).insertExploratory(userInstance);
-		verify(exploratoryDAO, never()).updateExploratoryStatus(any(StatusEnvBaseDTO.class));
-		verify(endpointService).get("test");
-		verifyNoMoreInteractions(exploratoryDAO);
-	}
-
-	@Test
-	public void createWhenMethodNewExploratoryCreateThrowsException() {
-		ProjectDTO projectDTO = getProjectDTO();
-		when(projectService.get(anyString())).thenReturn(projectDTO);
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-		doNothing().when(exploratoryDAO).insertExploratory(any(UserInstanceDTO.class));
-		ExploratoryGitCredsDTO egcDto = new ExploratoryGitCredsDTO();
-		when(gitCredsDAO.findGitCreds(anyString())).thenReturn(egcDto);
-
-		Exploratory exploratory = Exploratory.builder().name(EXPLORATORY_NAME).endpoint("test").build();
-
-		doThrow(new DlabException("Cannot create instance of resource class ")).when(requestBuilder)
-				.newExploratoryCreate(any(ProjectDTO.class), any(EndpointDTO.class), any(Exploratory.class),
-						any(UserInfo.class), any(ExploratoryGitCredsDTO.class), anyMapOf(String.class, String.class));
-
-		when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
-		try {
-            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());
-		}
-
-		statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("failed");
-
-		userInstance.withStatus("creating");
-		userInstance.withResources(Collections.emptyList());
-		verify(projectService).get("project");
-		verify(exploratoryDAO).insertExploratory(userInstance);
-		verify(exploratoryDAO).insertExploratory(userInstance);
-		verify(gitCredsDAO).findGitCreds(USER);
-		verify(requestBuilder).newExploratoryCreate(projectDTO, endpointDTO(), exploratory, userInfo, egcDto, Collections.emptyMap());
-		verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
-		verifyNoMoreInteractions(projectService, exploratoryDAO, gitCredsDAO, requestBuilder);
-	}
-
-	@Test
-	public void updateProjectExploratoryStatuses() {
-		when(exploratoryDAO.fetchProjectExploratoriesWhereStatusNotIn(anyString(), anyString(), anyVararg()))
-				.thenReturn(singletonList(userInstance));
-		when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
-		doNothing().when(computationalDAO).updateComputationalStatusesForExploratory(anyString(), anyString(),
-				anyString(), any(UserInstanceStatus.class), any(UserInstanceStatus.class), anyVararg());
-
-		exploratoryService.updateProjectExploratoryStatuses(userInfo, "project",
-				"endpoint", UserInstanceStatus.TERMINATING);
-		statusEnvBaseDTO = getStatusEnvBaseDTOWithStatus("terminating");
-
-		verify(exploratoryDAO).fetchProjectExploratoriesWhereStatusNotIn("project", "endpoint",
-				UserInstanceStatus.TERMINATED, UserInstanceStatus.FAILED);
-		verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
-		verify(computationalDAO).updateComputationalStatusesForExploratory(USER, PROJECT,
-				EXPLORATORY_NAME, UserInstanceStatus.TERMINATING, UserInstanceStatus.TERMINATING,
-				UserInstanceStatus.TERMINATED, UserInstanceStatus.FAILED);
-
-		verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
-	}
-
-	@Test
-	public void getUserInstance() {
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-
-        Optional<UserInstanceDTO> expectedInstance = Optional.of(userInstance);
-        Optional<UserInstanceDTO> actualInstance = exploratoryService.getUserInstance(USER, PROJECT, EXPLORATORY_NAME);
-        assertEquals(expectedInstance, actualInstance);
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verifyNoMoreInteractions(exploratoryDAO);
-    }
-
-	@Test
-	public void getUserInstanceWithException() {
-        doThrow(new ResourceNotFoundException("Exploratory for user not found"))
-                .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
-
-        Optional<UserInstanceDTO> expectedInstance = Optional.empty();
-        Optional<UserInstanceDTO> actualInstance = exploratoryService.getUserInstance(USER, PROJECT, EXPLORATORY_NAME);
-        assertEquals(expectedInstance, actualInstance);
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verifyNoMoreInteractions(exploratoryDAO);
-    }
-
-	@Test
-	public void testUpdateExploratoryClusterConfig() {
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
-        when(requestBuilder.newClusterConfigUpdate(any(UserInfo.class), any(UserInstanceDTO.class),
-                anyListOf(ClusterConfig.class), any(EndpointDTO.class))).thenReturn(new ExploratoryReconfigureSparkClusterActionDTO());
-        when(provisioningService.post(anyString(), anyString(), any(ExploratoryReconfigureSparkClusterActionDTO.class)
-                , any())).thenReturn(UUID);
-
-        exploratoryService.updateClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME, singletonList(new ClusterConfig()));
-
-        verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(requestBuilder).newClusterConfigUpdate(refEq(getUserInfo()), refEq(getUserInstanceDto()),
-                refEq(singletonList(new ClusterConfig())), refEq(endpointDTO()));
-        verify(requestId).put(USER, UUID);
-        verify(provisioningService).post(eq(endpointDTO().getUrl() + "exploratory/reconfigure_spark"), eq(TOKEN),
-                refEq(new ExploratoryReconfigureSparkClusterActionDTO(), "self"), eq(String.class));
-        verify(exploratoryDAO).updateExploratoryFields(refEq(new ExploratoryStatusDTO()
-                .withUser(USER)
-                .withProject(PROJECT)
-                .withConfig(singletonList(new ClusterConfig()))
-                .withStatus(UserInstanceStatus.RECONFIGURING.toString())
-                .withExploratoryName(EXPLORATORY_NAME), "self"));
-        verifyNoMoreInteractions(requestBuilder, requestId, exploratoryDAO, provisioningService);
-    }
-
-	@Test
-	public void testUpdateExploratoryClusterConfigWhenNotRunning() {
-
-        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenThrow(new ResourceNotFoundException("EXCEPTION"));
-
-        try {
-
-            exploratoryService.updateClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME,
-                    singletonList(new ClusterConfig()));
-        } catch (ResourceNotFoundException e) {
-            assertEquals("EXCEPTION", e.getMessage());
-        }
-
-        verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verifyNoMoreInteractions(exploratoryDAO);
-        verifyZeroInteractions(requestBuilder, requestId, provisioningService);
-    }
-
-	@Test
-	public void testGetClusterConfig() {
-        when(exploratoryDAO.getClusterConfig(anyString(), anyString(), anyString())).thenReturn(Collections.singletonList(getClusterConfig()));
-        final List<ClusterConfig> clusterConfig = exploratoryService.getClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME);
-
-        assertEquals(1, clusterConfig.size());
-        assertEquals("classification", clusterConfig.get(0).getClassification());
-
-        verify(exploratoryDAO).getClusterConfig(getUserInfo().getName(), PROJECT, EXPLORATORY_NAME);
-        verifyNoMoreInteractions(exploratoryDAO);
-    }
-
-	@Test
-	public void testGetClusterConfigWithException() {
-        when(exploratoryDAO.getClusterConfig(anyString(), anyString(), anyString())).thenThrow(new RuntimeException("Exception"));
-
-        expectedException.expect(RuntimeException.class);
-        expectedException.expectMessage("Exception");
-        exploratoryService.getClusterConfig(getUserInfo(), PROJECT, EXPLORATORY_NAME);
-    }
-
-	private ClusterConfig getClusterConfig() {
-		final ClusterConfig config = new ClusterConfig();
-		config.setClassification("classification");
-		return config;
-	}
-
-	private UserInfo getUserInfo() {
-		return new UserInfo(USER, TOKEN);
-	}
-
-	private UserInstanceDTO getUserInstanceDto() {
-        UserComputationalResource compResource = new UserComputationalResource();
-        compResource.setImageName("YYYY.dataengine");
-        compResource.setComputationalName("compName");
-        compResource.setStatus("stopped");
-        compResource.setComputationalId("compId");
-        return new UserInstanceDTO()
-                .withUser(USER)
-                .withExploratoryName(EXPLORATORY_NAME)
-                .withStatus("running")
-                .withResources(singletonList(compResource))
-                .withTags(Collections.emptyMap())
-                .withProject(PROJECT)
-                .withEndpoint("test")
-                .withCloudProvider(CloudProvider.AWS.toString());
-    }
-
-	private StatusEnvBaseDTO getStatusEnvBaseDTOWithStatus(String status) {
-		return new ExploratoryStatusDTO()
-                .withProject(PROJECT)
-				.withUser(USER)
-				.withExploratoryName(EXPLORATORY_NAME)
-				.withStatus(status);
-	}
-
-	private EndpointDTO endpointDTO() {
-		return new EndpointDTO("test", "url", "", null, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
-	}
-
-	private ProjectDTO getProjectDTO() {
-		return new ProjectDTO("project", Collections.emptySet(), "", "", null,
-				singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING,
-						new EdgeInfo())), true);
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/GitCredentialServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/GitCredentialServiceImplTest.java
deleted file mode 100644
index 8b8acaa..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/GitCredentialServiceImplTest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.GitCredsDAO;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryGitCredsUpdateDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class GitCredentialServiceImplTest {
-
-	private final String USER = "test";
-
-	@Mock
-	private GitCredsDAO gitCredsDAO;
-	@Mock
-	private ExploratoryDAO exploratoryDAO;
-	@Mock
-	private RESTService provisioningService;
-	@Mock
-	private RequestBuilder requestBuilder;
-	@Mock
-	private RequestId requestId;
-	@Mock
-	private EndpointService endpointService;
-
-	@InjectMocks
-	private GitCredentialServiceImpl gitCredentialService;
-
-	@Test
-	public void updateGitCredentials() {
-		String token = "token";
-		UserInfo userInfo = new UserInfo(USER, token);
-		doNothing().when(gitCredsDAO).updateGitCreds(anyString(), any(ExploratoryGitCredsDTO.class));
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-
-		String exploratoryName = "explName";
-		UserInstanceDTO uiDto = new UserInstanceDTO().withExploratoryName(exploratoryName).withUser(USER);
-		when(exploratoryDAO.fetchRunningExploratoryFields(anyString())).thenReturn(Collections.singletonList(uiDto));
-
-		ExploratoryGitCredsUpdateDTO egcuDto = new ExploratoryGitCredsUpdateDTO().withExploratoryName(exploratoryName);
-		when(requestBuilder.newGitCredentialsUpdate(any(UserInfo.class), any(UserInstanceDTO.class), any(EndpointDTO.class),
-				any(ExploratoryGitCredsDTO.class))).thenReturn(egcuDto);
-
-		String uuid = "someUuid";
-		when(provisioningService.post(anyString(), anyString(), any(ExploratoryGitCredsUpdateDTO.class), any()))
-				.thenReturn(uuid);
-		when(requestId.put(anyString(), anyString())).thenReturn(uuid);
-
-		ExploratoryGitCredsDTO egcDto = new ExploratoryGitCredsDTO();
-		gitCredentialService.updateGitCredentials(userInfo, egcDto);
-
-		verify(gitCredsDAO).updateGitCreds(USER, egcDto);
-		verify(exploratoryDAO).fetchRunningExploratoryFields(USER);
-		verify(requestBuilder).newGitCredentialsUpdate(userInfo, uiDto, endpointDTO(), egcDto);
-		verify(provisioningService).post(endpointDTO().getUrl() + "exploratory/git_creds", token, egcuDto,
-				String.class);
-		verify(requestId).put(USER, uuid);
-		verifyNoMoreInteractions(gitCredsDAO, exploratoryDAO, requestBuilder, provisioningService, requestId);
-	}
-
-	@Test
-	public void updateGitCredentialsWhenMethodUpdateGitCredsThrowsException() {
-		String token = "token";
-		UserInfo userInfo = new UserInfo(USER, token);
-		doThrow(new NullPointerException())
-				.when(gitCredsDAO).updateGitCreds(anyString(), any(ExploratoryGitCredsDTO.class));
-
-		ExploratoryGitCredsDTO egcDto = new ExploratoryGitCredsDTO();
-		try {
-			gitCredentialService.updateGitCredentials(userInfo, egcDto);
-		} catch (DlabException e) {
-			assertEquals("Cannot update the GIT credentials: null", e.getMessage());
-		}
-
-		verify(gitCredsDAO).updateGitCreds(USER, egcDto);
-		verifyNoMoreInteractions(gitCredsDAO);
-	}
-
-	@Test
-	public void updateGitCredentialsWithFailedNotebooks() {
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-		String token = "token";
-		UserInfo userInfo = new UserInfo(USER, token);
-		doNothing().when(gitCredsDAO).updateGitCreds(anyString(), any(ExploratoryGitCredsDTO.class));
-
-		String exploratoryName = "explName";
-		UserInstanceDTO uiDto = new UserInstanceDTO().withExploratoryName(exploratoryName).withUser(USER);
-		when(exploratoryDAO.fetchRunningExploratoryFields(anyString())).thenReturn(Collections.singletonList(uiDto));
-
-		doThrow(new DlabException("Cannot create instance of resource class "))
-				.when(requestBuilder).newGitCredentialsUpdate(any(UserInfo.class), any(UserInstanceDTO.class),
-				any(EndpointDTO.class), any(ExploratoryGitCredsDTO.class));
-
-		ExploratoryGitCredsDTO egcDto = new ExploratoryGitCredsDTO();
-		try {
-			gitCredentialService.updateGitCredentials(userInfo, egcDto);
-		} catch (DlabException e) {
-			assertEquals("Cannot update the GIT credentials: Requests for notebooks failed: explName",
-					e.getMessage());
-		}
-
-		verify(gitCredsDAO).updateGitCreds(USER, egcDto);
-		verify(exploratoryDAO).fetchRunningExploratoryFields(USER);
-		verify(requestBuilder).newGitCredentialsUpdate(userInfo, uiDto, endpointDTO(), egcDto);
-		verifyNoMoreInteractions(gitCredsDAO, exploratoryDAO, requestBuilder);
-	}
-
-	@Test
-	public void getGitCredentials() {
-		ExploratoryGitCredsDTO expectedEgcDto = new ExploratoryGitCredsDTO();
-		when(gitCredsDAO.findGitCreds(anyString(), anyBoolean())).thenReturn(expectedEgcDto);
-
-		ExploratoryGitCredsDTO actualEgcDto = gitCredentialService.getGitCredentials(USER);
-		assertNotNull(actualEgcDto);
-		assertEquals(expectedEgcDto, actualEgcDto);
-
-		verify(gitCredsDAO).findGitCreds(USER, true);
-		verifyNoMoreInteractions(gitCredsDAO);
-	}
-
-	@Test
-	public void getGitCredentialsWhenMethodFindGitCredsThrowsException() {
-		doThrow(new NullPointerException()).when(gitCredsDAO).findGitCreds(anyString(), anyBoolean());
-		try {
-			gitCredentialService.getGitCredentials(USER);
-		} catch (DlabException e) {
-			assertEquals("Cannot load GIT credentials for user test: null", e.getMessage());
-		}
-		verify(gitCredsDAO).findGitCreds(USER, true);
-		verifyNoMoreInteractions(gitCredsDAO);
-	}
-
-	private EndpointDTO endpointDTO() {
-		return new EndpointDTO("test", "url", "", null, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ImageExploratoryServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ImageExploratoryServiceImplTest.java
deleted file mode 100644
index ded7347..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ImageExploratoryServiceImplTest.java
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryLibDAO;
-import com.epam.dlab.backendapi.dao.ImageExploratoryDAO;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.resources.dto.ImageInfoRecord;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryImageDTO;
-import com.epam.dlab.dto.exploratory.ExploratoryStatusDTO;
-import com.epam.dlab.dto.exploratory.ImageStatus;
-import com.epam.dlab.dto.exploratory.LibStatus;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceAlreadyExistException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.model.ResourceType;
-import com.epam.dlab.model.exploratory.Image;
-import com.epam.dlab.model.library.Library;
-import com.epam.dlab.rest.client.RESTService;
-import com.mongodb.client.result.UpdateResult;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.anyVararg;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class ImageExploratoryServiceImplTest {
-	private final static String AUDIT_MESSAGE = "Image name: %s";
-	private final String USER = "test";
-	private final String TOKEN = "token";
-	private final String EXPLORATORY_NAME = "expName";
-	private final String PROJECT = "project";
-
-	private UserInfo userInfo;
-	private UserInstanceDTO userInstance;
-	private Image image;
-
-	@Mock
-	private ExploratoryDAO exploratoryDAO;
-	@Mock
-	private ImageExploratoryDAO imageExploratoryDao;
-	@Mock
-	private ExploratoryLibDAO libDAO;
-	@Mock
-	private RESTService provisioningService;
-	@Mock
-	private RequestBuilder requestBuilder;
-	@Mock
-	private EndpointService endpointService;
-	@Mock
-	private ProjectService projectService;
-
-	@InjectMocks
-	private ImageExploratoryServiceImpl imageExploratoryService;
-
-	@Rule
-	public ExpectedException expectedException = ExpectedException.none();
-
-	@Before
-	public void setUp() {
-		userInfo = getUserInfo();
-		userInstance = getUserInstanceDto();
-		image = fetchImage();
-	}
-
-	@Test
-	public void createImage() {
-		when(projectService.get(anyString())).thenReturn(getProjectDTO());
-		when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-		when(imageExploratoryDao.exist(anyString(), anyString())).thenReturn(false);
-
-		when(libDAO.getLibraries(anyString(), anyString(), anyString())).thenReturn(Collections.singletonList(getLibrary()));
-		doNothing().when(imageExploratoryDao).save(any(Image.class));
-		when(exploratoryDAO.updateExploratoryStatus(any(ExploratoryStatusDTO.class)))
-				.thenReturn(mock(UpdateResult.class));
-		ExploratoryImageDTO eiDto = new ExploratoryImageDTO();
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-		when(requestBuilder.newExploratoryImageCreate(any(UserInfo.class), any(UserInstanceDTO.class), anyString(),
-				any(EndpointDTO.class), any(ProjectDTO.class))).thenReturn(eiDto);
-
-		String expectedUuid = "someUuid";
-		when(provisioningService.post(anyString(), anyString(), any(ExploratoryImageDTO.class), any()))
-				.thenReturn(expectedUuid);
-
-		String imageName = "someImageName", imageDescription = "someDescription";
-		String actualUuid = imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME,
-				imageName, imageDescription, String.format(AUDIT_MESSAGE, imageName));
-		assertNotNull(actualUuid);
-		assertEquals(expectedUuid, actualUuid);
-
-		verify(projectService).get(PROJECT);
-		verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-		verify(exploratoryDAO).updateExploratoryStatus(any(ExploratoryStatusDTO.class));
-		verify(imageExploratoryDao).exist(imageName, PROJECT);
-		verify(imageExploratoryDao).save(any(Image.class));
-		verify(libDAO).getLibraries(USER, PROJECT, EXPLORATORY_NAME);
-		verify(requestBuilder).newExploratoryImageCreate(userInfo, userInstance, imageName, endpointDTO(), getProjectDTO());
-		verify(endpointService).get(anyString());
-		verify(provisioningService).post(endpointDTO().getUrl() + "exploratory/image", TOKEN, eiDto, String.class);
-		verifyNoMoreInteractions(projectService, exploratoryDAO, imageExploratoryDao, libDAO, requestBuilder, endpointService, provisioningService);
-	}
-
-	@Test
-	public void createImageWhenMethodFetchRunningExploratoryFieldsThrowsException() {
-		doThrow(new DlabException("Running exploratory instance for user with name not found."))
-				.when(exploratoryDAO).fetchRunningExploratoryFields(anyString(), anyString(), anyString());
-
-		String imageName = "someImageName", imageDescription = "someDescription";
-
-		try {
-			imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME, imageName, imageDescription, String.format(AUDIT_MESSAGE, imageName));
-		} catch (DlabException e) {
-			assertEquals("Running exploratory instance for user with name not found.", e.getMessage());
-		}
-		verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-		verifyNoMoreInteractions(exploratoryDAO);
-	}
-
-	@Test
-	public void createImageWhenResourceAlreadyExists() {
-		when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-		when(imageExploratoryDao.exist(anyString(), anyString())).thenReturn(true);
-
-		expectedException.expect(ResourceAlreadyExistException.class);
-		expectedException.expectMessage("Image with name someImageName is already exist");
-
-		String imageName = "someImageName", imageDescription = "someDescription";
-		imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME, imageName, imageDescription, String.format(AUDIT_MESSAGE, imageName));
-	}
-
-	@Test
-	public void createImageWhenMethodNewExploratoryImageCreateThrowsException() {
-		when(projectService.get(anyString())).thenReturn(getProjectDTO());
-		when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-		when(imageExploratoryDao.exist(anyString(), anyString())).thenReturn(false);
-
-		when(libDAO.getLibraries(anyString(), anyString(), anyString())).thenReturn(Collections.singletonList(getLibrary()));
-		doNothing().when(imageExploratoryDao).save(any(Image.class));
-		when(exploratoryDAO.updateExploratoryStatus(any(ExploratoryStatusDTO.class)))
-				.thenReturn(mock(UpdateResult.class));
-		doThrow(new DlabException("Cannot create instance of resource class")).when(requestBuilder)
-				.newExploratoryImageCreate(any(UserInfo.class), any(UserInstanceDTO.class), anyString(), any(EndpointDTO.class), any(ProjectDTO.class));
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-
-		String imageName = "someImageName", imageDescription = "someDescription";
-		try {
-			imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME, imageName, imageDescription, String.format(AUDIT_MESSAGE, imageName));
-		} catch (DlabException e) {
-			assertEquals("Cannot create instance of resource class", e.getMessage());
-		}
-
-		verify(projectService).get(PROJECT);
-		verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-		verify(exploratoryDAO).updateExploratoryStatus(any(ExploratoryStatusDTO.class));
-		verify(imageExploratoryDao).exist(imageName, PROJECT);
-		verify(imageExploratoryDao).save(any(Image.class));
-		verify(libDAO).getLibraries(USER, PROJECT, EXPLORATORY_NAME);
-		verify(requestBuilder).newExploratoryImageCreate(userInfo, userInstance, imageName, endpointDTO(), getProjectDTO());
-		verify(endpointService).get(anyString());
-		verifyNoMoreInteractions(projectService, exploratoryDAO, imageExploratoryDao, libDAO, requestBuilder, endpointService);
-	}
-
-	@Test
-	public void finishImageCreate() {
-		when(exploratoryDAO.updateExploratoryStatus(any(ExploratoryStatusDTO.class)))
-				.thenReturn(mock(UpdateResult.class));
-		doNothing().when(imageExploratoryDao).updateImageFields(any(Image.class));
-		doNothing().when(exploratoryDAO).updateExploratoryIp(anyString(), anyString(), anyString(), anyString());
-
-		String notebookIp = "someIp";
-		imageExploratoryService.finishImageCreate(image, EXPLORATORY_NAME, notebookIp);
-
-		verify(exploratoryDAO).updateExploratoryStatus(any(ExploratoryStatusDTO.class));
-		verify(exploratoryDAO).updateExploratoryIp(USER, PROJECT, notebookIp, EXPLORATORY_NAME);
-		verify(imageExploratoryDao).updateImageFields(image);
-		verifyNoMoreInteractions(exploratoryDAO, imageExploratoryDao);
-	}
-
-	@Test
-	public void finishImageCreateWhenMethodUpdateExploratoryIpThrowsException() {
-		when(exploratoryDAO.updateExploratoryStatus(any(ExploratoryStatusDTO.class)))
-				.thenReturn(mock(UpdateResult.class));
-		doNothing().when(imageExploratoryDao).updateImageFields(any(Image.class));
-		doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
-				.when(exploratoryDAO).updateExploratoryIp(anyString(), anyString(), anyString(), anyString());
-
-		String notebookIp = "someIp";
-		try {
-			imageExploratoryService.finishImageCreate(image, EXPLORATORY_NAME, notebookIp);
-		} catch (ResourceNotFoundException e) {
-			assertEquals("Exploratory for user with name not found", e.getMessage());
-		}
-
-		verify(exploratoryDAO).updateExploratoryStatus(any(ExploratoryStatusDTO.class));
-		verify(exploratoryDAO).updateExploratoryIp(USER, PROJECT, notebookIp, EXPLORATORY_NAME);
-		verify(imageExploratoryDao).updateImageFields(image);
-		verifyNoMoreInteractions(exploratoryDAO, imageExploratoryDao);
-	}
-
-	@Test
-	public void finishImageCreateWhenNotebookIpIsNull() {
-		when(exploratoryDAO.updateExploratoryStatus(any(ExploratoryStatusDTO.class)))
-				.thenReturn(mock(UpdateResult.class));
-		doNothing().when(imageExploratoryDao).updateImageFields(any(Image.class));
-
-		imageExploratoryService.finishImageCreate(image, EXPLORATORY_NAME, null);
-
-		verify(exploratoryDAO).updateExploratoryStatus(any(ExploratoryStatusDTO.class));
-		verify(exploratoryDAO, never()).updateExploratoryIp(USER, PROJECT, null, EXPLORATORY_NAME);
-		verify(imageExploratoryDao).updateImageFields(image);
-		verifyNoMoreInteractions(exploratoryDAO, imageExploratoryDao);
-	}
-
-	@Test
-	public void getCreatedImages() {
-		ImageInfoRecord imageInfoRecord = getImageInfoRecord();
-		List<ImageInfoRecord> expectedRecordList = Collections.singletonList(imageInfoRecord);
-		when(imageExploratoryDao.getImages(anyString(), anyString(), anyString(), anyString(), anyVararg()))
-				.thenReturn(expectedRecordList);
-
-		List<ImageInfoRecord> actualRecordList = imageExploratoryService.getNotFailedImages(USER,
-				"someImage", "someProject", "someEndpoint");
-		assertNotNull(actualRecordList);
-		assertEquals(1, actualRecordList.size());
-		assertEquals(expectedRecordList, actualRecordList);
-
-		verify(imageExploratoryDao).getImages(USER, "someImage", "someProject", "someEndpoint", ImageStatus.CREATED, ImageStatus.CREATING);
-		verifyNoMoreInteractions(imageExploratoryDao);
-	}
-
-	@Test
-	public void getImage() {
-		ImageInfoRecord expectedImageInfoRecord = getImageInfoRecord();
-		when(imageExploratoryDao.getImage(anyString(), anyString(), anyString(), anyString()))
-				.thenReturn(Optional.of(expectedImageInfoRecord));
-
-		ImageInfoRecord actualImageInfoRecord = imageExploratoryService.getImage(USER, "someName", "someProject", "someEndpoint");
-		assertNotNull(actualImageInfoRecord);
-		assertEquals(expectedImageInfoRecord, actualImageInfoRecord);
-
-		verify(imageExploratoryDao).getImage(USER, "someName", "someProject", "someEndpoint");
-		verifyNoMoreInteractions(imageExploratoryDao);
-	}
-
-	@Test
-	public void getImageWhenMethodGetImageReturnsOptionalEmpty() {
-		when(imageExploratoryDao.getImage(anyString(), anyString(), anyString(), anyString())).thenReturn(Optional.empty());
-		expectedException.expect(ResourceNotFoundException.class);
-		expectedException.expectMessage(String.format("Image with name %s was not found for user %s",
-				"someImageName", USER));
-		imageExploratoryService.getImage(USER, "someImageName", "someProject", "someEndpoint");
-	}
-
-	@Test
-	public void getImagesForProject() {
-		when(imageExploratoryDao.getImagesForProject(anyString())).thenReturn(Collections.singletonList(getImageInfoRecord()));
-
-		imageExploratoryService.getImagesForProject(PROJECT);
-
-		verify(imageExploratoryDao).getImagesForProject(PROJECT);
-		verifyNoMoreInteractions(imageExploratoryDao);
-	}
-
-	private ImageInfoRecord getImageInfoRecord() {
-		return new ImageInfoRecord("someName", "someDescription", "someProject", "someEndpoint", "someUser", "someApp",
-				"someFullName", ImageStatus.CREATED);
-	}
-
-	private Image fetchImage() {
-		return Image.builder()
-				.name("someImageName")
-				.description("someDescription")
-				.status(ImageStatus.CREATING)
-				.user(USER)
-				.project(PROJECT)
-				.libraries(Collections.singletonList(getLibrary()))
-				.computationalLibraries(Collections.emptyMap())
-				.dockerImage("someImageName")
-				.exploratoryId("explId").build();
-	}
-
-	private Library getLibrary() {
-		return new Library("someGroup", "someName", "someVersion", LibStatus.INSTALLED,
-				"someErrorMessage").withType(ResourceType.EXPLORATORY);
-	}
-
-	private UserInstanceDTO getUserInstanceDto() {
-		return new UserInstanceDTO()
-				.withUser(USER)
-				.withExploratoryName(EXPLORATORY_NAME)
-				.withExploratoryId("explId")
-				.withProject(PROJECT);
-	}
-
-	private UserInfo getUserInfo() {
-		return new UserInfo(USER, TOKEN);
-	}
-
-	private EndpointDTO endpointDTO() {
-		return new EndpointDTO("test", "url", "", null, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
-	}
-
-	private ProjectDTO getProjectDTO() {
-		return ProjectDTO.builder().name(PROJECT).build();
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceImplTest.java
deleted file mode 100644
index 5a3caa3..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceImplTest.java
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.domain.BillingReport;
-import com.epam.dlab.backendapi.domain.BillingReportLine;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.domain.ProjectEndpointDTO;
-import com.epam.dlab.backendapi.resources.TestBase;
-import com.epam.dlab.backendapi.resources.dto.HealthStatusPageDTO;
-import com.epam.dlab.backendapi.resources.dto.ProjectInfrastructureInfo;
-import com.epam.dlab.backendapi.service.BillingService;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.dto.InfrastructureMetaInfoDTO;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.aws.edge.EdgeInfoAws;
-import com.epam.dlab.dto.azure.edge.EdgeInfoAzure;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.billing.BillingResourceType;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.dto.gcp.edge.EdgeInfoGcp;
-import com.jcabi.manifests.Manifests;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyListOf;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class InfrastructureInfoServiceImplTest extends TestBase {
-
-	private static final String PROJECT = "project";
-	private static final String EXPLORATORY_NAME = "exploratoryName";
-	private static final String COMPUTE_NAME = "computeName";
-	private static final String CURRENCY = "currency";
-
-	@Mock
-	private ExploratoryDAO expDAO;
-	@Mock
-	private SelfServiceApplicationConfiguration configuration;
-	@Mock
-	private ProjectService projectService;
-	@Mock
-	private EndpointService endpointService;
-	@Mock
-	private BillingService billingService;
-
-	@InjectMocks
-	private InfrastructureInfoServiceImpl infoService;
-
-	@Test
-	public void getUserResources() {
-		when(endpointService.getEndpoints()).thenReturn(Collections.singletonList(getEndpointDTO()));
-		when(projectService.getUserProjects(any(UserInfo.class), anyBoolean())).thenReturn(Collections.singletonList(getProjectDTO()));
-		when(expDAO.findExploratories(anyString(), anyString())).thenReturn(getUserInstanceDTOs());
-		when(billingService.getBillingProjectQuoteUsed(anyString())).thenReturn(10);
-		when(projectService.get(anyString())).thenReturn(getProjectDTO());
-		when(billingService.getExploratoryBillingData(anyString(), anyString(), anyString(), anyListOf(String.class))).thenReturn(getReport());
-
-		List<ProjectInfrastructureInfo> actualUserResources = infoService.getUserResources(getUserInfo());
-
-		assertEquals("resources should be equal", getProjectInfrastructureInfo(), actualUserResources);
-		verify(endpointService).getEndpoints();
-		verify(projectService).getUserProjects(getUserInfo(), Boolean.FALSE);
-		verify(expDAO).findExploratories(USER.toLowerCase(), PROJECT);
-		verify(billingService).getBillingProjectQuoteUsed(PROJECT);
-		verify(projectService).get(PROJECT);
-		verify(billingService).getExploratoryBillingData(PROJECT, ENDPOINT_NAME, EXPLORATORY_NAME, Collections.singletonList(COMPUTE_NAME));
-		verifyNoMoreInteractions(endpointService, projectService, expDAO, billingService);
-	}
-
-	@Test
-	public void getAwsUserResources() {
-		when(endpointService.getEndpoints()).thenReturn(Collections.singletonList(getEndpointDTO()));
-		when(projectService.getUserProjects(any(UserInfo.class), anyBoolean())).thenReturn(Collections.singletonList(getAwsProjectDTO()));
-		when(expDAO.findExploratories(anyString(), anyString())).thenReturn(getUserInstanceDTOs());
-		when(billingService.getBillingProjectQuoteUsed(anyString())).thenReturn(10);
-		when(projectService.get(anyString())).thenReturn(getAwsProjectDTO());
-		when(billingService.getExploratoryBillingData(anyString(), anyString(), anyString(), anyListOf(String.class))).thenReturn(getReport());
-
-		List<ProjectInfrastructureInfo> actualUserResources = infoService.getUserResources(getUserInfo());
-
-		assertEquals("resources should be equal", getAwsProjectInfrastructureInfo(), actualUserResources);
-		verify(endpointService).getEndpoints();
-		verify(projectService).getUserProjects(getUserInfo(), Boolean.FALSE);
-		verify(expDAO).findExploratories(USER.toLowerCase(), PROJECT);
-		verify(billingService).getBillingProjectQuoteUsed(PROJECT);
-		verify(projectService).get(PROJECT);
-		verify(billingService).getExploratoryBillingData(PROJECT, ENDPOINT_NAME, EXPLORATORY_NAME, Collections.singletonList(COMPUTE_NAME));
-		verifyNoMoreInteractions(endpointService, projectService, expDAO, billingService);
-	}
-
-	@Test
-	public void getAzureUserResources() {
-		when(endpointService.getEndpoints()).thenReturn(Collections.singletonList(getEndpointDTO()));
-		when(projectService.getUserProjects(any(UserInfo.class), anyBoolean())).thenReturn(Collections.singletonList(getAzureProjectDTO()));
-		when(expDAO.findExploratories(anyString(), anyString())).thenReturn(getUserInstanceDTOs());
-		when(billingService.getBillingProjectQuoteUsed(anyString())).thenReturn(10);
-		when(projectService.get(anyString())).thenReturn(getAzureProjectDTO());
-		when(billingService.getExploratoryBillingData(anyString(), anyString(), anyString(), anyListOf(String.class))).thenReturn(getReport());
-
-		List<ProjectInfrastructureInfo> actualUserResources = infoService.getUserResources(getUserInfo());
-
-		assertEquals("resources should be equal", getAzureProjectInfrastructureInfo(), actualUserResources);
-		verify(endpointService).getEndpoints();
-		verify(projectService).getUserProjects(getUserInfo(), Boolean.FALSE);
-		verify(expDAO).findExploratories(USER.toLowerCase(), PROJECT);
-		verify(billingService).getBillingProjectQuoteUsed(PROJECT);
-		verify(projectService).get(PROJECT);
-		verify(billingService).getExploratoryBillingData(PROJECT, ENDPOINT_NAME, EXPLORATORY_NAME, Collections.singletonList(COMPUTE_NAME));
-		verifyNoMoreInteractions(endpointService, projectService, expDAO, billingService);
-	}
-
-	@Test
-	public void getGcpUserResources() {
-		when(endpointService.getEndpoints()).thenReturn(Collections.singletonList(getEndpointDTO()));
-		when(projectService.getUserProjects(any(UserInfo.class), anyBoolean())).thenReturn(Collections.singletonList(getGcpProjectDTO()));
-		when(expDAO.findExploratories(anyString(), anyString())).thenReturn(getUserInstanceDTOs());
-		when(billingService.getBillingProjectQuoteUsed(anyString())).thenReturn(10);
-		when(projectService.get(anyString())).thenReturn(getGcpProjectDTO());
-		when(billingService.getExploratoryBillingData(anyString(), anyString(), anyString(), anyListOf(String.class))).thenReturn(getReport());
-
-		List<ProjectInfrastructureInfo> actualUserResources = infoService.getUserResources(getUserInfo());
-
-		assertEquals("resources should be equal", getGcpProjectInfrastructureInfo(), actualUserResources);
-		verify(endpointService).getEndpoints();
-		verify(projectService).getUserProjects(getUserInfo(), Boolean.FALSE);
-		verify(expDAO).findExploratories(USER.toLowerCase(), PROJECT);
-		verify(billingService).getBillingProjectQuoteUsed(PROJECT);
-		verify(projectService).get(PROJECT);
-		verify(billingService).getExploratoryBillingData(PROJECT, ENDPOINT_NAME, EXPLORATORY_NAME, Collections.singletonList(COMPUTE_NAME));
-		verifyNoMoreInteractions(endpointService, projectService, expDAO, billingService);
-	}
-
-	@Test
-	public void getHeathStatus() {
-		when(configuration.isBillingSchedulerEnabled()).thenReturn(Boolean.TRUE);
-		when(configuration.isAuditEnabled()).thenReturn(Boolean.TRUE);
-		when(projectService.isAnyProjectAssigned(any(UserInfo.class))).thenReturn(Boolean.TRUE);
-
-		HealthStatusPageDTO actualHeathStatus = infoService.getHeathStatus(getUserInfo());
-
-		assertEquals("HealthStatusPageDTO should be equal", getHealthStatusPageDTO(), actualHeathStatus);
-		verify(projectService).isAnyProjectAssigned(getUserInfo());
-		verify(configuration).isBillingSchedulerEnabled();
-		verify(configuration).isAuditEnabled();
-		verifyNoMoreInteractions(configuration, projectService);
-	}
-
-	@Test
-	public void getInfrastructureMetaInfo() {
-		Manifests.DEFAULT.put("GIT-Branch", "branch");
-		Manifests.DEFAULT.put("GIT-Commit", "commit");
-		Manifests.DEFAULT.put("DLab-Version", "version");
-
-		InfrastructureMetaInfoDTO actualInfrastructureMetaInfo = infoService.getInfrastructureMetaInfo();
-
-		assertEquals("InfrastructureMetaInfoDTO should be equal", getInfrastructureMetaInfoDTO(), actualInfrastructureMetaInfo);
-	}
-
-	private InfrastructureMetaInfoDTO getInfrastructureMetaInfoDTO() {
-		return InfrastructureMetaInfoDTO.builder()
-				.branch("branch")
-				.commit("commit")
-				.version("version")
-				.releaseNotes("https://github.com/apache/incubator-dlab/blob/branch/RELEASE_NOTES.md")
-				.build();
-	}
-
-	private HealthStatusPageDTO getHealthStatusPageDTO() {
-		return HealthStatusPageDTO.builder()
-				.status("ok")
-				.listResources(Collections.emptyList())
-				.billingEnabled(Boolean.TRUE)
-				.auditEnabled(Boolean.TRUE)
-				.projectAdmin(Boolean.FALSE)
-				.admin(Boolean.FALSE)
-				.projectAssigned(Boolean.TRUE)
-				.bucketBrowser(HealthStatusPageDTO.BucketBrowser.builder()
-						.view(Boolean.TRUE)
-						.upload(Boolean.TRUE)
-						.download(Boolean.TRUE)
-						.delete(Boolean.TRUE)
-						.build())
-				.build();
-	}
-
-	private List<ProjectInfrastructureInfo> getProjectInfrastructureInfo() {
-		List<ProjectInfrastructureInfo> objects = new ArrayList<>();
-		objects.add(ProjectInfrastructureInfo.builder()
-				.project(PROJECT)
-				.billingQuoteUsed(10)
-				.shared(Collections.singletonMap(ENDPOINT_NAME, Collections.emptyMap()))
-				.exploratory(getUserInstanceDTOs())
-				.exploratoryBilling(Collections.singletonList(getReport()))
-				.endpoints(Collections.singletonList(getEndpointDTO()))
-				.build());
-		return objects;
-	}
-
-	private List<ProjectInfrastructureInfo> getAwsProjectInfrastructureInfo() {
-		List<ProjectInfrastructureInfo> objects = new ArrayList<>();
-		objects.add(ProjectInfrastructureInfo.builder()
-				.project(PROJECT)
-				.billingQuoteUsed(10)
-				.shared(Collections.singletonMap(ENDPOINT_NAME, getAwsEdgeInfo()))
-				.exploratory(getUserInstanceDTOs())
-				.exploratoryBilling(Collections.singletonList(getReport()))
-				.endpoints(Collections.singletonList(getEndpointDTO()))
-				.build());
-		return objects;
-	}
-
-	private List<ProjectInfrastructureInfo> getAzureProjectInfrastructureInfo() {
-		List<ProjectInfrastructureInfo> objects = new ArrayList<>();
-		objects.add(ProjectInfrastructureInfo.builder()
-				.project(PROJECT)
-				.billingQuoteUsed(10)
-				.shared(Collections.singletonMap(ENDPOINT_NAME, getAzureEdgeInfo()))
-				.exploratory(getUserInstanceDTOs())
-				.exploratoryBilling(Collections.singletonList(getReport()))
-				.endpoints(Collections.singletonList(getEndpointDTO()))
-				.build());
-		return objects;
-	}
-
-	private List<ProjectInfrastructureInfo> getGcpProjectInfrastructureInfo() {
-		List<ProjectInfrastructureInfo> objects = new ArrayList<>();
-		objects.add(ProjectInfrastructureInfo.builder()
-				.project(PROJECT)
-				.billingQuoteUsed(10)
-				.shared(Collections.singletonMap(ENDPOINT_NAME, getGcpEdgeInfo()))
-				.exploratory(getUserInstanceDTOs())
-				.exploratoryBilling(Collections.singletonList(getReport()))
-				.endpoints(Collections.singletonList(getEndpointDTO()))
-				.build());
-		return objects;
-	}
-
-	private Map<String, String> getAwsEdgeInfo() {
-		HashMap<String, String> edge = new HashMap<>();
-		edge.put("status", "running");
-		edge.put("edge_node_ip", "publicIp");
-		edge.put("user_own_bicket_name", "ownBucketName");
-		edge.put("shared_bucket_name", "sharedBucketName");
-		return edge;
-	}
-
-	private Map<String, String> getAzureEdgeInfo() {
-		HashMap<String, String> edge = new HashMap<>();
-		edge.put("status", "running");
-		edge.put("edge_node_ip", "publicIp");
-		edge.put("user_container_name", "userContainerName");
-		edge.put("shared_container_name", "sharedContainerName");
-		edge.put("user_storage_account_name", "userStorageAccountName");
-		edge.put("shared_storage_account_name", "sharedStorageAccountName");
-		edge.put("datalake_name", "dataLakeName");
-		edge.put("datalake_user_directory_name", "dataLakeDirectoryName");
-		edge.put("datalake_shared_directory_name", "dataLakeSharedDirectoryName");
-		return edge;
-	}
-
-	private Map<String, String> getGcpEdgeInfo() {
-		HashMap<String, String> edge = new HashMap<>();
-		edge.put("status", "running");
-		edge.put("edge_node_ip", "publicIp");
-		edge.put("user_own_bucket_name", "ownBucketName");
-		edge.put("shared_bucket_name", "sharedBucketName");
-		return edge;
-	}
-
-	private ProjectDTO getProjectDTO() {
-		return ProjectDTO.builder()
-				.name(PROJECT)
-				.endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, null)))
-				.build();
-	}
-
-	private ProjectDTO getAwsProjectDTO() {
-		EdgeInfoAws edgeInfoAws = new EdgeInfoAws();
-		edgeInfoAws.setPublicIp("publicIp");
-		edgeInfoAws.setUserOwnBucketName("ownBucketName");
-		edgeInfoAws.setSharedBucketName("sharedBucketName");
-
-		return ProjectDTO.builder()
-				.name(PROJECT)
-				.endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, edgeInfoAws)))
-				.build();
-	}
-
-	private ProjectDTO getAzureProjectDTO() {
-		EdgeInfoAzure edgeInfoAzure = new EdgeInfoAzure();
-		edgeInfoAzure.setPublicIp("publicIp");
-		edgeInfoAzure.setUserContainerName("userContainerName");
-		edgeInfoAzure.setSharedContainerName("sharedContainerName");
-		edgeInfoAzure.setUserStorageAccountName("userStorageAccountName");
-		edgeInfoAzure.setSharedStorageAccountName("sharedStorageAccountName");
-		edgeInfoAzure.setDataLakeName("dataLakeName");
-		edgeInfoAzure.setDataLakeDirectoryName("dataLakeDirectoryName");
-		edgeInfoAzure.setDataLakeSharedDirectoryName("dataLakeSharedDirectoryName");
-
-		return ProjectDTO.builder()
-				.name(PROJECT)
-				.endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, edgeInfoAzure)))
-				.build();
-	}
-
-	private ProjectDTO getGcpProjectDTO() {
-		EdgeInfoGcp edgeInfoGcp = new EdgeInfoGcp();
-		edgeInfoGcp.setPublicIp("publicIp");
-		edgeInfoGcp.setUserOwnBucketName("ownBucketName");
-		edgeInfoGcp.setSharedBucketName("sharedBucketName");
-
-		return ProjectDTO.builder()
-				.name(PROJECT)
-				.endpoints(Collections.singletonList(new ProjectEndpointDTO(ENDPOINT_NAME, UserInstanceStatus.RUNNING, edgeInfoGcp)))
-				.build();
-	}
-
-	private List<UserInstanceDTO> getUserInstanceDTOs() {
-		return Collections.singletonList(
-				new UserInstanceDTO().withUser(USER).withProject(PROJECT).withExploratoryName(EXPLORATORY_NAME).withEndpoint(ENDPOINT_NAME)
-						.withResources(Collections.singletonList(getCompute()))
-		);
-	}
-
-	private UserComputationalResource getCompute() {
-		UserComputationalResource resource = new UserComputationalResource();
-		resource.setComputationalName(COMPUTE_NAME);
-		resource.setImageName(DataEngineType.SPARK_STANDALONE.getName());
-
-		return resource;
-	}
-
-	private BillingReport getReport() {
-		BillingReportLine line1 = BillingReportLine.builder().cost(1.0).user(USER).resourceType(BillingResourceType.EXPLORATORY).project(PROJECT).endpoint(ENDPOINT_NAME)
-				.resourceName(EXPLORATORY_NAME).currency(CURRENCY).build();
-		BillingReportLine line2 = BillingReportLine.builder().cost(1.0).user(USER).resourceType(BillingResourceType.COMPUTATIONAL).project(PROJECT).endpoint(ENDPOINT_NAME)
-				.resourceName(COMPUTE_NAME).exploratoryName(EXPLORATORY_NAME).currency(CURRENCY).build();
-		List<BillingReportLine> billingReportLines = Arrays.asList(line1, line2);
-
-		return BillingReport.builder()
-				.name(EXPLORATORY_NAME)
-				.reportLines(billingReportLines)
-				.totalCost(2.0)
-				.currency(CURRENCY)
-				.build();
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java
deleted file mode 100644
index 769b0de..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
-import com.epam.dlab.backendapi.dao.ProjectDAO;
-import com.epam.dlab.backendapi.dao.SettingsDAO;
-import com.epam.dlab.backendapi.dao.UserGroupDAO;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.base.computational.FullComputationalTemplate;
-import com.epam.dlab.dto.imagemetadata.ComputationalMetadataDTO;
-import com.epam.dlab.dto.imagemetadata.ComputationalResourceShapeDto;
-import com.epam.dlab.dto.imagemetadata.ExploratoryMetadataDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.lang.reflect.Field;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class InfrastructureTemplateServiceBaseTest {
-
-	@Mock
-	private SettingsDAO settingsDAO;
-	@Mock
-	private RESTService provisioningService;
-	@Mock
-	private ProjectDAO projectDAO;
-	@Mock
-	private EndpointService endpointService;
-	@Mock
-	private UserGroupDAO userGroupDao;
-	@Mock
-	private SelfServiceApplicationConfiguration configuration;
-
-	@InjectMocks
-	private InfrastructureTemplateServiceBaseChild infrastructureTemplateServiceBaseChild =
-			new InfrastructureTemplateServiceBaseChild();
-
-	@Test
-	public void getExploratoryTemplates() {
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-		ExploratoryMetadataDTO emDto1 = new ExploratoryMetadataDTO("someImage1");
-		HashMap<String, List<ComputationalResourceShapeDto>> shapes1 = new HashMap<>();
-		shapes1.put("Memory optimized", Arrays.asList(
-				new ComputationalResourceShapeDto("Standard_E4s_v3", "someSize", "someDescription",
-						"someRam", 2),
-				new ComputationalResourceShapeDto("Standard_E32s_v3", "someSize2", "someDescription2",
-						"someRam2", 5)));
-		emDto1.setExploratoryEnvironmentShapes(shapes1);
-
-		ExploratoryMetadataDTO emDto2 = new ExploratoryMetadataDTO("someImage2");
-		HashMap<String, List<ComputationalResourceShapeDto>> shapes2 = new HashMap<>();
-		shapes2.put("Compute optimized", Arrays.asList(
-				new ComputationalResourceShapeDto("Standard_F2s", "someSize", "someDescription",
-						"someRam", 3),
-				new ComputationalResourceShapeDto("Standard_F16s", "someSize2", "someDescription2",
-						"someRam2", 6)));
-		emDto2.setExploratoryEnvironmentShapes(shapes2);
-		List<ExploratoryMetadataDTO> expectedEmdDtoList = Arrays.asList(emDto1, emDto2);
-		when(userGroupDao.getUserGroups(anyString())).thenReturn(Collections.emptySet());
-		when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(expectedEmdDtoList.toArray());
-		when(settingsDAO.getConfOsFamily()).thenReturn("someConfOsFamily");
-
-		UserInfo userInfo = new UserInfo("test", "token");
-		List<ExploratoryMetadataDTO> actualEmdDtoList =
-				infrastructureTemplateServiceBaseChild.getExploratoryTemplates(userInfo, "project", "endpoint");
-		assertNotNull(actualEmdDtoList);
-		assertEquals(expectedEmdDtoList, actualEmdDtoList);
-
-		verify(provisioningService).get(endpointDTO().getUrl() + "docker/exploratory", "token", ExploratoryMetadataDTO[].class);
-		verify(settingsDAO, times(2)).getConfOsFamily();
-		verify(userGroupDao).getUserGroups("test");
-		verifyNoMoreInteractions(provisioningService, settingsDAO, userGroupDao);
-	}
-
-	@Test
-	public void getExploratoryTemplatesWithException() {
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-		doThrow(new DlabException("Could not load list of exploratory templates for user"))
-				.when(provisioningService).get(anyString(), anyString(), any(Class.class));
-
-		UserInfo userInfo = new UserInfo("test", "token");
-		try {
-			infrastructureTemplateServiceBaseChild.getExploratoryTemplates(userInfo, "project", "endpoint");
-		} catch (DlabException e) {
-			assertEquals("Could not load list of exploratory templates for user", e.getMessage());
-		}
-		verify(provisioningService).get(endpointDTO().getUrl() + "docker/exploratory", "token", ExploratoryMetadataDTO[].class);
-		verifyNoMoreInteractions(provisioningService);
-	}
-
-	@Test
-	public void getComputationalTemplates() throws NoSuchFieldException, IllegalAccessException {
-
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-		final ComputationalMetadataDTO computationalMetadataDTO = new ComputationalMetadataDTO("dataengine-service");
-		computationalMetadataDTO.setComputationResourceShapes(Collections.emptyMap());
-		List<ComputationalMetadataDTO> expectedCmdDtoList = Collections.singletonList(
-				computationalMetadataDTO
-		);
-		when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
-				null, null, null, null, true)));
-		when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(expectedCmdDtoList.toArray(new ComputationalMetadataDTO[]{}));
-
-		List<FullComputationalTemplate> expectedFullCmdDtoList = expectedCmdDtoList.stream()
-				.map(e -> infrastructureTemplateServiceBaseChild.getCloudFullComputationalTemplate(e))
-				.collect(Collectors.toList());
-
-		UserInfo userInfo = new UserInfo("test", "token");
-		List<FullComputationalTemplate> actualFullCmdDtoList =
-				infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project", "endpoint");
-		assertNotNull(actualFullCmdDtoList);
-		assertEquals(expectedFullCmdDtoList.size(), actualFullCmdDtoList.size());
-		for (int i = 0; i < expectedFullCmdDtoList.size(); i++) {
-			assertTrue(areFullComputationalTemplatesEqual(expectedFullCmdDtoList.get(i), actualFullCmdDtoList.get(i)));
-		}
-
-		verify(provisioningService).get(endpointDTO().getUrl() + "docker/computational", "token", ComputationalMetadataDTO[].class);
-		verifyNoMoreInteractions(provisioningService);
-	}
-
-	@Test
-	public void getComputationalTemplatesWhenMethodThrowsException() {
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-		doThrow(new DlabException("Could not load list of computational templates for user"))
-				.when(provisioningService).get(anyString(), anyString(), any(Class.class));
-
-		UserInfo userInfo = new UserInfo("test", "token");
-		try {
-			infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project", "endpoint");
-		} catch (DlabException e) {
-			assertEquals("Could not load list of computational templates for user", e.getMessage());
-		}
-		verify(provisioningService).get(endpointDTO().getUrl() + "docker/computational", "token",
-				ComputationalMetadataDTO[].class);
-		verifyNoMoreInteractions(provisioningService);
-	}
-
-	@Test
-	public void getComputationalTemplatesWithInapproprietaryImageName() {
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-		final ComputationalMetadataDTO computationalMetadataDTO = new ComputationalMetadataDTO("dataengine-service");
-		computationalMetadataDTO.setComputationResourceShapes(Collections.emptyMap());
-		List<ComputationalMetadataDTO> expectedCmdDtoList = Collections.singletonList(computationalMetadataDTO);
-		when(provisioningService.get(anyString(), anyString(), any(Class.class))).thenReturn(expectedCmdDtoList.toArray(new ComputationalMetadataDTO[]{}));
-		when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
-				null, null, null, null, true)));
-		when(configuration.getMinEmrInstanceCount()).thenReturn(1);
-		when(configuration.getMaxEmrInstanceCount()).thenReturn(2);
-		when(configuration.getMaxEmrSpotInstanceBidPct()).thenReturn(3);
-		when(configuration.getMinEmrSpotInstanceBidPct()).thenReturn(4);
-
-		UserInfo userInfo = new UserInfo("test", "token");
-		try {
-			infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project", "endpoint");
-		} catch (IllegalArgumentException e) {
-			assertEquals("Unknown data engine null", e.getMessage());
-		}
-		verify(provisioningService).get(endpointDTO().getUrl() + "docker/computational", "token", ComputationalMetadataDTO[].class);
-		verifyNoMoreInteractions(provisioningService);
-	}
-
-	private boolean areFullComputationalTemplatesEqual(FullComputationalTemplate object1,
-													   FullComputationalTemplate object2) throws NoSuchFieldException,
-			IllegalAccessException {
-		Field computationalMetadataDTO1 = object1.getClass().getDeclaredField("computationalMetadataDTO");
-		computationalMetadataDTO1.setAccessible(true);
-		Field computationalMetadataDTO2 = object2.getClass().getSuperclass().getDeclaredField("computationalMetadataDTO");
-		computationalMetadataDTO2.setAccessible(true);
-		return computationalMetadataDTO1.get(object1).equals(computationalMetadataDTO2.get(object2));
-	}
-
-	private EndpointDTO endpointDTO() {
-		return new EndpointDTO("test", "url", "", null, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
-	}
-
-	private class InfrastructureTemplateServiceBaseChild extends InfrastructureTemplateServiceImpl {
-
-		protected FullComputationalTemplate getCloudFullComputationalTemplate(ComputationalMetadataDTO metadataDTO) {
-			return new FullComputationalTemplate(metadataDTO);
-		}
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/LibraryServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/LibraryServiceImplTest.java
deleted file mode 100644
index 2528383..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/LibraryServiceImplTest.java
+++ /dev/null
@@ -1,490 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryLibDAO;
-import com.epam.dlab.backendapi.domain.EndpointDTO;
-import com.epam.dlab.backendapi.domain.NotebookTemplate;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.resources.dto.LibInfoRecord;
-import com.epam.dlab.backendapi.resources.dto.LibInstallFormDTO;
-import com.epam.dlab.backendapi.resources.dto.LibKey;
-import com.epam.dlab.backendapi.resources.dto.LibraryStatus;
-import com.epam.dlab.backendapi.service.EndpointService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.cloud.CloudProvider;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.dto.exploratory.LibInstallDTO;
-import com.epam.dlab.dto.exploratory.LibStatus;
-import com.epam.dlab.dto.exploratory.LibraryInstallDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.model.library.Library;
-import com.epam.dlab.rest.client.RESTService;
-import org.bson.Document;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyListOf;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class LibraryServiceImplTest {
-
-	private static final String LIB_NAME = "name";
-	private static final String LIB_GROUP = "group";
-	private static final String LIB_VERSION = "version";
-	private static final String UUID = "id";
-	private final String USER = "test";
-	private final String EXPLORATORY_NAME = "explName";
-	private final String PROJECT = "projectName";
-	private final String COMPUTATIONAL_NAME = "compName";
-
-	private static final String GROUP_JAVA = "java";
-	private static final String GROUP_PIP2 = "pip2";
-	private static final String GROUP_PIP3 = "pip3";
-	private static final String GROUP_R_PKG = "r_pkg";
-	private static final String GROUP_OS_PKG = "os_pkg";
-	private static final String GROUP_OTHERS = "others";
-
-	private LibInstallDTO liDto;
-	private List<LibInstallDTO> libs;
-	private LibInstallFormDTO libInstallFormDTO;
-	private LibraryInstallDTO libraryInstallDto;
-
-	@Mock
-	private ExploratoryDAO exploratoryDAO;
-	@Mock
-	private ExploratoryLibDAO libraryDAO;
-    @Mock
-    private RequestBuilder requestBuilder;
-    @Mock
-    private RequestId requestId;
-    @Mock
-    private RESTService provisioningService;
-    @Mock
-    private EndpointService endpointService;
-
-    @Rule
-	public ExpectedException expectedException = ExpectedException.none();
-
-	@InjectMocks
-	private LibraryServiceImpl libraryService;
-
-	@Before
-	public void setUp() {
-		prepareForTesting();
-	}
-
-	@Test
-	public void testGetLibs() {
-        Document document = new Document();
-        when(libraryDAO.findExploratoryLibraries(anyString(), anyString(), anyString())).thenReturn(document);
-
-        List<Document> expectedList = new ArrayList<>();
-        List<Document> actualList = libraryService.getLibs(USER, PROJECT, EXPLORATORY_NAME, "");
-        assertNotNull(actualList);
-        assertEquals(expectedList, actualList);
-
-        verify(libraryDAO).findExploratoryLibraries(USER, PROJECT, EXPLORATORY_NAME);
-        verifyNoMoreInteractions(libraryDAO);
-    }
-
-	@Test
-	public void getLibInfo() {
-        Document document = new Document();
-        when(libraryDAO.findAllLibraries(anyString(), anyString(), anyString())).thenReturn(document);
-
-        List<LibInfoRecord> expectedList = new ArrayList<>();
-        List<LibInfoRecord> actualList = libraryService.getLibInfo(USER, PROJECT, EXPLORATORY_NAME);
-        assertNotNull(actualList);
-        assertEquals(expectedList, actualList);
-
-        verify(libraryDAO).findAllLibraries(USER, PROJECT, EXPLORATORY_NAME);
-        verifyNoMoreInteractions(libraryDAO);
-    }
-
-	@Test
-	public void getLibInfoWhenListsOfExploratoryAndComputationalLibsAreNotEmpty() {
-        when(libraryDAO.findAllLibraries(anyString(), anyString(), anyString()))
-                .thenReturn(getDocumentWithExploratoryAndComputationalLibs());
-
-        List<LibInfoRecord> expectedList = getLibInfoRecordList();
-        List<LibInfoRecord> actualList = libraryService.getLibInfo(USER, PROJECT, EXPLORATORY_NAME);
-        assertNotNull(actualList);
-        assertEquals(expectedList, actualList);
-
-        verify(libraryDAO).findAllLibraries(USER, PROJECT, EXPLORATORY_NAME);
-        verifyNoMoreInteractions(libraryDAO);
-    }
-
-	@Test
-	public void installComputationalLibsWithoutOverride() {
-        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
-        final List<LibInstallDTO> libsToInstall = getLibs("installing");
-        libraryInstallDTO.setLibs(libsToInstall);
-        final UserInfo user = getUser();
-
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
-        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
-        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class),
-                any(UserComputationalResource.class), anyListOf(LibInstallDTO.class), any(EndpointDTO.class))).thenReturn(libraryInstallDTO);
-
-
-        final String uuid = libraryService.installComputationalLibs(user, PROJECT, EXPLORATORY_NAME,
-                COMPUTATIONAL_NAME, getLibs(null), null);
-
-        assertEquals(UUID, uuid);
-
-        verify(libraryDAO).getLibrary(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME, LIB_GROUP, LIB_NAME);
-        verify(requestBuilder).newLibInstall(refEq(user), refEq(getUserInstanceDto()),
-                refEq(getUserComputationalResourceWithName(COMPUTATIONAL_NAME)), eq(libsToInstall), refEq(endpointDTO()));
-        verify(provisioningService).post(eq(endpointDTO().getUrl() + "library/computational/lib_install"), eq(user.getAccessToken()),
-                refEq(libraryInstallDTO), eq(String.class));
-        verify(libraryDAO).addLibrary(eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME),
-                eq(COMPUTATIONAL_NAME), refEq(libsToInstall.get(0)), eq(false));
-        verify(requestId).put(user.getName(), UUID);
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
-        verifyNoMoreInteractions(libraryDAO, requestBuilder, provisioningService, requestId, exploratoryDAO);
-    }
-
-	@Test
-	public void installComputationalLibsWhenComputationalNotFound() {
-        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
-        final List<LibInstallDTO> libsToInstall = getLibs("installing");
-        libraryInstallDTO.setLibs(libsToInstall);
-        libraryInstallDTO.setProject(PROJECT);
-        final UserInfo user = getUser();
-
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
-        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
-        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class),
-                any(UserComputationalResource.class), anyListOf(LibInstallDTO.class), any(EndpointDTO.class)))
-                .thenReturn(libraryInstallDTO);
-
-
-        expectedException.expect(DlabException.class);
-        expectedException.expectMessage("Computational with name " + COMPUTATIONAL_NAME + "X was not found");
-
-        libraryService.installComputationalLibs(user, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME + "X", getLibs(null), null);
-    }
-
-	@Test
-	public void installComputationalLibsWithOverride() {
-        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
-        final List<LibInstallDTO> libsToInstall = getLibs("installing");
-        libraryInstallDTO.setProject(PROJECT);
-        libraryInstallDTO.setLibs(libsToInstall);
-        final UserInfo user = getUser();
-
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
-        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
-        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class),
-                any(UserComputationalResource.class), anyListOf(LibInstallDTO.class), any(EndpointDTO.class)))
-                .thenReturn(libraryInstallDTO);
-        when(libraryDAO.getLibrary(anyString(), anyString(), anyString(), anyString(), anyString(), anyString())).thenReturn(getLibrary(LibStatus.INSTALLED));
-
-        final String uuid = libraryService.installComputationalLibs(user, PROJECT, EXPLORATORY_NAME,
-                COMPUTATIONAL_NAME, getLibs(null), null);
-
-        assertEquals(UUID, uuid);
-
-        libsToInstall.get(0).setOverride(true);
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
-        verify(libraryDAO).getLibrary(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME, LIB_GROUP, LIB_NAME);
-        verify(libraryDAO).addLibrary(eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME),
-                eq(COMPUTATIONAL_NAME), refEq(libsToInstall.get(0)), eq(true));
-        verify(requestBuilder).newLibInstall(refEq(user), refEq(getUserInstanceDto()),
-                refEq(getUserComputationalResourceWithName(COMPUTATIONAL_NAME)), eq(libsToInstall), refEq(endpointDTO()));
-        verify(provisioningService).post(eq(endpointDTO().getUrl() + "library/computational/lib_install"),
-                eq(user.getAccessToken()),
-                refEq(libraryInstallDTO), eq(String.class));
-        verify(requestId).put(user.getName(), UUID);
-        verifyNoMoreInteractions(libraryDAO, requestBuilder, provisioningService, requestId, exploratoryDAO);
-
-    }
-
-
-	@Test
-	public void installComputationalLibsWhenLibraryIsAlreadyInstalling() {
-        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
-        final List<LibInstallDTO> libsToInstall = getLibs("installing");
-        libraryInstallDTO.setLibs(libsToInstall);
-        final UserInfo user = getUser();
-
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
-        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
-        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class),
-                any(UserComputationalResource.class), anyListOf(LibInstallDTO.class), any(EndpointDTO.class)))
-                .thenReturn(libraryInstallDTO);
-        when(libraryDAO.getLibrary(anyString(), anyString(), anyString(), anyString(), anyString(), anyString())).thenReturn(getLibrary(LibStatus.INSTALLING));
-
-        try {
-            libraryService.installComputationalLibs(user, PROJECT, EXPLORATORY_NAME,
-                    COMPUTATIONAL_NAME, getLibs(null), null);
-        } catch (DlabException e) {
-            assertEquals("Library name is already installing", e.getMessage());
-        }
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
-        verify(libraryDAO).getLibrary(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME, LIB_GROUP, LIB_NAME);
-        verifyNoMoreInteractions(libraryDAO, requestBuilder, provisioningService, requestId, exploratoryDAO);
-    }
-
-	@Test
-	public void installExploratoryLibsWithoutOverride() {
-        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
-        final List<LibInstallDTO> libsToInstall = getLibs("installing");
-        libraryInstallDTO.setLibs(libsToInstall);
-        final UserInfo user = getUser();
-
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
-        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
-        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class), any(EndpointDTO.class),
-                anyListOf(LibInstallDTO.class))).thenReturn(libraryInstallDTO);
-
-
-        final String uuid = libraryService.installExploratoryLibs(user, PROJECT, EXPLORATORY_NAME, getLibs(null), null);
-
-        assertEquals(UUID, uuid);
-
-        verify(libraryDAO).getLibrary(USER, PROJECT, EXPLORATORY_NAME, LIB_GROUP, LIB_NAME);
-        verify(requestBuilder).newLibInstall(refEq(user), refEq(getUserInstanceDto()), eq(endpointDTO()), eq(libsToInstall));
-        verify(provisioningService).post(eq(endpointDTO().getUrl() + "library/exploratory/lib_install"), eq(user.getAccessToken()),
-                refEq(libraryInstallDTO), eq(String.class));
-        verify(libraryDAO).addLibrary(eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME), refEq(libsToInstall.get(0)), eq(false));
-        verify(requestId).put(user.getName(), UUID);
-        verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verifyNoMoreInteractions(libraryDAO, requestBuilder, provisioningService, requestId, exploratoryDAO);
-    }
-
-	@Test
-	public void installExploratoryLibsWithOverride() {
-        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
-        final List<LibInstallDTO> libsToInstall = getLibs("installing");
-        libraryInstallDTO.setLibs(libsToInstall);
-        final UserInfo user = getUser();
-
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
-        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
-        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class), any(EndpointDTO.class),
-                anyListOf(LibInstallDTO.class))).thenReturn(libraryInstallDTO);
-        when(libraryDAO.getLibrary(anyString(), anyString(), anyString(), anyString(), anyString())).thenReturn(getLibrary(LibStatus.INSTALLED));
-
-        final String uuid = libraryService.installExploratoryLibs(user, PROJECT, EXPLORATORY_NAME, getLibs(null), null);
-
-        assertEquals(UUID, uuid);
-
-        libsToInstall.get(0).setOverride(true);
-        verify(libraryDAO).getLibrary(USER, PROJECT, EXPLORATORY_NAME, LIB_GROUP, LIB_NAME);
-        verify(libraryDAO).addLibrary(eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME), refEq(libsToInstall.get(0)), eq(true));
-        verify(requestBuilder).newLibInstall(refEq(user), refEq(getUserInstanceDto()), eq(endpointDTO()), eq(libsToInstall));
-        verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(provisioningService).post(eq(endpointDTO().getUrl() + "library/exploratory/lib_install"), eq(user.getAccessToken()),
-                refEq(libraryInstallDTO), eq(String.class));
-        verify(requestId).put(USER, uuid);
-        verifyNoMoreInteractions(libraryDAO, requestBuilder, provisioningService, requestId, exploratoryDAO);
-    }
-
-	@Test
-	public void installExploratoryLibsWhenLibIsAlreadyInstalling() {
-        final LibraryInstallDTO libraryInstallDTO = new LibraryInstallDTO();
-        final List<LibInstallDTO> libsToInstall = getLibs("installing");
-        libraryInstallDTO.setLibs(libsToInstall);
-        final UserInfo user = getUser();
-
-        when(endpointService.get(anyString())).thenReturn(endpointDTO());
-        when(exploratoryDAO.fetchRunningExploratoryFields(anyString(), anyString(), anyString())).thenReturn(getUserInstanceDto());
-        when(provisioningService.post(anyString(), anyString(), any(LibraryInstallDTO.class), any())).thenReturn(UUID);
-        when(requestBuilder.newLibInstall(any(UserInfo.class), any(UserInstanceDTO.class), any(EndpointDTO.class),
-                anyListOf(LibInstallDTO.class))).thenReturn(libraryInstallDTO);
-        when(libraryDAO.getLibrary(anyString(), anyString(), anyString(), anyString(), anyString())).thenReturn(getLibrary(LibStatus.INSTALLING));
-
-        try {
-            libraryService.installExploratoryLibs(user, PROJECT, EXPLORATORY_NAME, getLibs(null), null);
-        } catch (DlabException e) {
-	        assertEquals("Library name is already installing", e.getMessage());
-        }
-
-		verify(libraryDAO).getLibrary(USER, PROJECT, EXPLORATORY_NAME, LIB_GROUP, LIB_NAME);
-		verify(exploratoryDAO).fetchRunningExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-		verifyNoMoreInteractions(libraryDAO, requestBuilder, provisioningService, requestId, exploratoryDAO);
-
-	}
-
-	@Test
-	public void getComputeLibGroups() {
-		List<Object> computeGroups = Arrays.asList(GROUP_PIP3, GROUP_OTHERS, GROUP_R_PKG, GROUP_OS_PKG, GROUP_JAVA);
-
-		List<String> computeGroupsResult = libraryService.getComputeLibGroups();
-
-		assertEquals("lists are not equal", computeGroups, computeGroupsResult);
-	}
-
-	@Test
-	public void getExploratoryJupyterLibGroups() {
-		List<Object> exploratoryGroups = Arrays.asList(GROUP_PIP2, GROUP_PIP3, GROUP_OTHERS, GROUP_OS_PKG, GROUP_R_PKG, GROUP_JAVA);
-		when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(getJupyterUserInstanceDtoForLibGroups());
-
-		List<String> exploratoryGroupsResult = libraryService.getExploratoryLibGroups(getUser(), PROJECT, EXPLORATORY_NAME);
-
-		assertEquals("lists are not equal", exploratoryGroups, exploratoryGroupsResult);
-		verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-	}
-
-	@Test
-	public void getExploratoryRstudioLibGroups() {
-		List<Object> exploratoryGroups = Arrays.asList(GROUP_PIP2, GROUP_PIP3, GROUP_OTHERS, GROUP_OS_PKG, GROUP_R_PKG);
-		when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(getRstudioUserInstanceDtoForLibGroups());
-
-		List<String> exploratoryGroupsResult = libraryService.getExploratoryLibGroups(getUser(), PROJECT, EXPLORATORY_NAME);
-
-		assertEquals("lists are not equal", exploratoryGroups, exploratoryGroupsResult);
-		verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-	}
-
-	private Library getLibrary(LibStatus status) {
-		return new Library(LIB_GROUP, LIB_NAME, "1", status, "");
-	}
-
-	private List<LibInstallDTO> getLibs(String status) {
-		final LibInstallDTO libInstallDTO = new LibInstallDTO(LIB_GROUP, LIB_NAME, LIB_VERSION);
-		libInstallDTO.setStatus(status);
-		return Collections.singletonList(libInstallDTO);
-	}
-
-	private UserInfo getUser() {
-		return new UserInfo(USER, "token123");
-	}
-
-	private void prepareForTesting() {
-		liDto = new LibInstallDTO("someGroup", "someName", "someVersion");
-		libs = Collections.singletonList(liDto);
-		libInstallFormDTO = new LibInstallFormDTO();
-		libInstallFormDTO.setNotebookName(EXPLORATORY_NAME);
-		libInstallFormDTO.setComputationalName(COMPUTATIONAL_NAME);
-		libInstallFormDTO.setLibs(libs);
-		libraryInstallDto = new LibraryInstallDTO().withExploratoryName(EXPLORATORY_NAME)
-				.withComputationalName(COMPUTATIONAL_NAME).withApplicationName("");
-		libraryInstallDto.setLibs(new ArrayList<>());
-	}
-
-	private UserComputationalResource getUserComputationalResourceWithName(String name) {
-		UserComputationalResource resource = new UserComputationalResource();
-		resource.setComputationalName(name);
-		resource.setComputationalId("someId");
-		resource.setImageName("someImageName");
-		return resource;
-	}
-
-	private UserInstanceDTO getUserInstanceDto() {
-		final UserInstanceDTO userInstanceDTO = new UserInstanceDTO().withUser(USER).withExploratoryName(EXPLORATORY_NAME);
-		userInstanceDTO.getResources().add(getUserComputationalResourceWithName(COMPUTATIONAL_NAME));
-		return userInstanceDTO;
-	}
-
-	private UserInstanceDTO getJupyterUserInstanceDtoForLibGroups() {
-		return new UserInstanceDTO()
-				.withUser(USER)
-				.withExploratoryName(EXPLORATORY_NAME)
-				.withTemplateName(NotebookTemplate.JUPYTER.getName());
-	}
-
-	private UserInstanceDTO getRstudioUserInstanceDtoForLibGroups() {
-		return new UserInstanceDTO()
-				.withUser(USER)
-				.withExploratoryName(EXPLORATORY_NAME)
-				.withTemplateName(NotebookTemplate.RSTUDIO.getName());
-	}
-
-	private List<Document> getExpLibsList() {
-		Document explLibsDoc = new Document();
-		explLibsDoc.append(ExploratoryLibDAO.LIB_NAME, "expLibName");
-		explLibsDoc.append(ExploratoryLibDAO.LIB_VERSION, "expLibVersion");
-		explLibsDoc.append(ExploratoryLibDAO.LIB_GROUP, "expLibGroup");
-		explLibsDoc.append(ExploratoryLibDAO.STATUS, "expLibStatus");
-		explLibsDoc.append(ExploratoryLibDAO.ERROR_MESSAGE, "expLibErrorMessage");
-		return Collections.singletonList(explLibsDoc);
-	}
-
-	private Document getCompLibs() {
-		Document compLibs = new Document();
-		compLibs.append(ExploratoryLibDAO.LIB_NAME, "compLibName");
-		compLibs.append(ExploratoryLibDAO.LIB_VERSION, "compLibVersion");
-		compLibs.append(ExploratoryLibDAO.LIB_GROUP, "compLibGroup");
-		compLibs.append(ExploratoryLibDAO.STATUS, "compLibStatus");
-		compLibs.append(ExploratoryLibDAO.ERROR_MESSAGE, "compLibErrorMessage");
-
-		Document compResourcesAndLibs = new Document();
-		compResourcesAndLibs.append("compName", Collections.singletonList(compLibs));
-		return compResourcesAndLibs;
-	}
-
-	private Document getDocumentWithExploratoryAndComputationalLibs() {
-		return new Document().append(ExploratoryLibDAO.EXPLORATORY_LIBS, getExpLibsList())
-				.append(ExploratoryLibDAO.COMPUTATIONAL_LIBS, getCompLibs());
-	}
-
-	private List<LibInfoRecord> getLibInfoRecordList() {
-		LibKey explLibKey = new LibKey("expLibName", "expLibVersion", "expLibGroup");
-		List<LibraryStatus> explLibStatuses = Collections.singletonList(
-				new LibraryStatus(EXPLORATORY_NAME, "notebook", "expLibStatus", "expLibErrorMessage", null, null));
-
-		LibKey compLibKey = new LibKey("compLibName", "compLibVersion", "compLibGroup");
-		List<LibraryStatus> compLibStatuses = Collections.singletonList(
-				new LibraryStatus("compName", "cluster", "compLibStatus", "compLibErrorMessage", null, null));
-
-		return Arrays.asList(
-				new LibInfoRecord(compLibKey, compLibStatuses),
-				new LibInfoRecord(explLibKey, explLibStatuses)
-		);
-	}
-
-	private EndpointDTO endpointDTO() {
-		return new EndpointDTO("test", "url", "", null, EndpointDTO.EndpointStatus.ACTIVE, CloudProvider.AWS);
-	}
-
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/MavenCentralLibraryServiceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/MavenCentralLibraryServiceTest.java
deleted file mode 100644
index c42076d..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/MavenCentralLibraryServiceTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.domain.MavenSearchArtifactResponse;
-import com.epam.dlab.backendapi.resources.dto.LibraryDTO;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.rest.client.RESTService;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.net.URI;
-import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.refEq;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class MavenCentralLibraryServiceTest {
-
-	@Mock
-	private RESTService client;
-	@InjectMocks
-	private MavenCentralLibraryService mavenCentralLibraryService;
-	@Rule
-	public ExpectedException expectedException = ExpectedException.none();
-
-	@Test
-	public void getLibraryId() {
-		when(client.get(any(URI.class), any())).thenReturn(getMavenResponse());
-
-		final LibraryDTO libDTO = mavenCentralLibraryService.getLibrary("groupId", "artifactId", "version");
-
-		assertNotNull(libDTO);
-		assertEquals("groupId:artifactId", libDTO.getName());
-		assertEquals("version", libDTO.getVersion());
-
-		verify(client).get(refEq(URI.create("/solrsearch/select?q=a:%22artifactId%22+AND+g" +
-						":%22groupId%22+AND+v:%22version%22+AND+(p:%22jar%22%20OR%20p:%22bundle%22)" +
-						"&rows=20&wt=json&core=gav&p=jar")),
-				eq(MavenSearchArtifactResponse.class));
-	}
-
-	@Test
-	public void getLibraryIdWithException() {
-		when(client.get(any(URI.class), any())).thenThrow(new DlabException("Can not get artifact info from maven " +
-				"central due to: Exception"));
-
-		expectedException.expect(DlabException.class);
-		expectedException.expectMessage("Can not get artifact info from maven central due to: Exception");
-
-		mavenCentralLibraryService.getLibrary("groupId", "artifactId", "version");
-	}
-
-	private MavenSearchArtifactResponse getMavenResponse() {
-		final MavenSearchArtifactResponse response = new MavenSearchArtifactResponse();
-		MavenSearchArtifactResponse.Response.Artifact artifact = new MavenSearchArtifactResponse.Response.Artifact();
-		artifact.setId("test.group:artifact:1.0");
-		artifact.setVersion("1.0");
-		final MavenSearchArtifactResponse.Response rsp = new MavenSearchArtifactResponse.Response();
-		rsp.setArtifacts(Collections.singletonList(artifact));
-		response.setResponse(rsp);
-		return response;
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ReuploadKeyServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ReuploadKeyServiceImplTest.java
deleted file mode 100644
index 1aefbbb..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ReuploadKeyServiceImplTest.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.ComputationalDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.domain.RequestId;
-import com.epam.dlab.backendapi.service.ExploratoryService;
-import com.epam.dlab.backendapi.util.RequestBuilder;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyCallbackDTO;
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyStatus;
-import com.epam.dlab.dto.reuploadkey.ReuploadKeyStatusDTO;
-import com.epam.dlab.model.ResourceData;
-import com.epam.dlab.model.ResourceType;
-import com.epam.dlab.rest.client.RESTService;
-import com.mongodb.client.result.UpdateResult;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import static com.epam.dlab.dto.UserInstanceStatus.RUNNING;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class ReuploadKeyServiceImplTest {
-
-	private final String USER = "test";
-	private final String TOKEN = "token";
-	private final String EXPLORATORY_NAME = "explName";
-
-	private UserInfo userInfo;
-
-	@Mock
-	private RESTService provisioningService;
-	@Mock
-	private RequestBuilder requestBuilder;
-	@Mock
-	private RequestId requestId;
-	@Mock
-	private ExploratoryService exploratoryService;
-	@Mock
-	private ComputationalDAO computationalDAO;
-	@Mock
-	private ExploratoryDAO exploratoryDAO;
-
-	@InjectMocks
-	private ReuploadKeyServiceImpl reuploadKeyService;
-
-
-	@Rule
-	public ExpectedException expectedException = ExpectedException.none();
-
-	@Before
-	public void setUp() {
-		userInfo = getUserInfo();
-	}
-
-	@Test
-	public void updateResourceDataForEdgeWhenStatusCompleted() {
-		ResourceData resource = new ResourceData(ResourceType.EDGE, "someId", null, null);
-		ReuploadKeyStatusDTO dto = getReuploadKeyStatusDTO(resource, ReuploadKeyStatus.COMPLETED);
-
-		reuploadKeyService.updateResourceData(dto);
-
-		verifyZeroInteractions(exploratoryDAO, computationalDAO);
-	}
-
-	@Test
-	public void updateResourceDataForEdgeWhenStatusFailed() {
-		ResourceData resource = new ResourceData(ResourceType.EDGE, "someId", null, null);
-
-		ReuploadKeyStatusDTO dto = getReuploadKeyStatusDTO(resource, ReuploadKeyStatus.FAILED);
-		reuploadKeyService.updateResourceData(dto);
-
-		verifyZeroInteractions(exploratoryDAO, computationalDAO);
-	}
-
-	@Test
-	public void updateResourceDataForExploratoryWhenStatusCompleted() {
-		ResourceData resource = new ResourceData(ResourceType.EXPLORATORY, "someId", EXPLORATORY_NAME, null);
-		when(exploratoryDAO.updateStatusForExploratory(anyString(), anyString(), anyString(),
-				any(UserInstanceStatus.class))).thenReturn(mock(UpdateResult.class));
-		doNothing().when(exploratoryDAO).updateReuploadKeyForExploratory(anyString(), anyString(), anyString(), anyBoolean());
-
-		ReuploadKeyStatusDTO dto = getReuploadKeyStatusDTO(resource, ReuploadKeyStatus.COMPLETED);
-
-		reuploadKeyService.updateResourceData(dto);
-
-		verify(exploratoryDAO).updateStatusForExploratory(USER, null, EXPLORATORY_NAME, RUNNING);
-		verify(exploratoryDAO).updateReuploadKeyForExploratory(USER, null, EXPLORATORY_NAME, false);
-		verifyNoMoreInteractions(exploratoryDAO);
-		verifyZeroInteractions(computationalDAO);
-	}
-
-	@Test
-	public void updateResourceDataForExploratoryWhenStatusFailed() {
-		ResourceData resource = new ResourceData(ResourceType.EXPLORATORY, "someId", EXPLORATORY_NAME, null);
-		when(exploratoryDAO.updateStatusForExploratory(anyString(), anyString(), anyString(),
-				any(UserInstanceStatus.class))).thenReturn(mock(UpdateResult.class));
-
-		ReuploadKeyStatusDTO dto = getReuploadKeyStatusDTO(resource, ReuploadKeyStatus.FAILED);
-
-		reuploadKeyService.updateResourceData(dto);
-
-		verify(exploratoryDAO).updateStatusForExploratory(USER, null, EXPLORATORY_NAME, RUNNING);
-		verifyNoMoreInteractions(exploratoryDAO);
-		verifyZeroInteractions(computationalDAO);
-	}
-
-	@Test
-	public void updateResourceDataForClusterWhenStatusCompleted() {
-		ResourceData resource = new ResourceData(ResourceType.COMPUTATIONAL, "someId", EXPLORATORY_NAME, "compName");
-		doNothing().when(computationalDAO).updateStatusForComputationalResource(anyString(), anyString(), anyString(),
-				anyString(), any(UserInstanceStatus.class));
-		doNothing().when(computationalDAO).updateReuploadKeyFlagForComputationalResource(anyString(), anyString(),
-				anyString(), anyString(), anyBoolean());
-		ReuploadKeyStatusDTO dto = getReuploadKeyStatusDTO(resource, ReuploadKeyStatus.COMPLETED);
-
-		reuploadKeyService.updateResourceData(dto);
-
-		verify(computationalDAO).updateStatusForComputationalResource(USER, null, EXPLORATORY_NAME, "compName", RUNNING);
-		verify(computationalDAO).updateReuploadKeyFlagForComputationalResource(USER, null, EXPLORATORY_NAME,
-				"compName", false);
-		verifyNoMoreInteractions(computationalDAO);
-		verifyZeroInteractions(exploratoryDAO);
-	}
-
-	@Test
-	public void updateResourceDataForClusterWhenStatusFailed() {
-		ResourceData resource = new ResourceData(ResourceType.COMPUTATIONAL, "someId", EXPLORATORY_NAME, "compName");
-		doNothing().when(computationalDAO).updateStatusForComputationalResource(anyString(), anyString(), anyString(),
-				anyString(), any(UserInstanceStatus.class));
-		ReuploadKeyStatusDTO dto = getReuploadKeyStatusDTO(resource, ReuploadKeyStatus.FAILED);
-
-		reuploadKeyService.updateResourceData(dto);
-
-		verify(computationalDAO).updateStatusForComputationalResource(USER, null, EXPLORATORY_NAME, "compName", RUNNING);
-		verifyNoMoreInteractions(computationalDAO);
-		verifyZeroInteractions(exploratoryDAO);
-	}
-
-	private UserInfo getUserInfo() {
-		return new UserInfo(USER, TOKEN);
-	}
-
-	private ReuploadKeyStatusDTO getReuploadKeyStatusDTO(ResourceData resource, ReuploadKeyStatus status) {
-		return new ReuploadKeyStatusDTO().withReuploadKeyCallbackDto(
-				new ReuploadKeyCallbackDTO().withResource(resource)).withReuploadKeyStatus(status).withUser(USER);
-	}
-
-}
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
deleted file mode 100644
index 2721a51..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImplTest.java
+++ /dev/null
@@ -1,1125 +0,0 @@
-/*
- * 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.auth.UserInfo;
-import com.epam.dlab.backendapi.dao.ComputationalDAO;
-import com.epam.dlab.backendapi.dao.ExploratoryDAO;
-import com.epam.dlab.backendapi.dao.SchedulerJobDAO;
-import com.epam.dlab.backendapi.service.ComputationalService;
-import com.epam.dlab.backendapi.service.ExploratoryService;
-import com.epam.dlab.backendapi.service.SecurityService;
-import com.epam.dlab.dto.SchedulerJobDTO;
-import com.epam.dlab.dto.UserInstanceDTO;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.aws.computational.AwsComputationalResource;
-import com.epam.dlab.dto.base.DataEngineType;
-import com.epam.dlab.dto.computational.UserComputationalResource;
-import com.epam.dlab.exceptions.ResourceInappropriateStateException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import com.epam.dlab.model.scheduler.SchedulerJobData;
-import com.mongodb.client.result.UpdateResult;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.time.DayOfWeek;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.OffsetDateTime;
-import java.time.ZoneId;
-import java.time.temporal.ChronoUnit;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import static com.epam.dlab.dto.UserInstanceStatus.RUNNING;
-import static com.epam.dlab.dto.UserInstanceStatus.STARTING;
-import static com.epam.dlab.dto.UserInstanceStatus.STOPPED;
-import static com.epam.dlab.dto.UserInstanceStatus.STOPPING;
-import static java.util.Collections.singletonList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Matchers.anyVararg;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class SchedulerJobServiceImplTest {
-	private static final String AUDIT_MESSAGE = "Scheduled action, requested for notebook %s";
-	private final String USER = "test";
-	private final String EXPLORATORY_NAME = "explName";
-	private final String COMPUTATIONAL_NAME = "compName";
-	private final String PROJECT = "project";
-	private SchedulerJobDTO schedulerJobDTO;
-	private UserInstanceDTO userInstance;
-
-	@Mock
-	private SchedulerJobDAO schedulerJobDAO;
-	@Mock
-	private ExploratoryDAO exploratoryDAO;
-	@Mock
-	private ComputationalDAO computationalDAO;
-	@Mock
-	private SecurityService securityService;
-	@Mock
-	private ExploratoryService exploratoryService;
-	@Mock
-	private ComputationalService computationalService;
-
-	@InjectMocks
-	private SchedulerJobServiceImpl schedulerJobService;
-
-
-	@Before
-	public void setUp() {
-		schedulerJobDTO = getSchedulerJobDTO(LocalDate.now(), LocalDate.now().plusDays(1),
-				Arrays.asList(DayOfWeek.values()), Arrays.asList(DayOfWeek.values()), false,
-				LocalDateTime.of(LocalDate.now(), LocalTime.now().truncatedTo(ChronoUnit.MINUTES)),
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		userInstance = getUserInstanceDTO();
-	}
-
-	@Test
-	public void fetchSchedulerJobForUserAndExploratory() {
-		when(schedulerJobDAO.fetchSingleSchedulerJobByUserAndExploratory(anyString(), anyString(), anyString()))
-				.thenReturn(Optional.of(schedulerJobDTO));
-
-		SchedulerJobDTO actualSchedulerJobDto =
-				schedulerJobService.fetchSchedulerJobForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME);
-		assertNotNull(actualSchedulerJobDto);
-		assertEquals(schedulerJobDTO, actualSchedulerJobDto);
-
-		verify(schedulerJobDAO).fetchSingleSchedulerJobByUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME);
-		verifyNoMoreInteractions(exploratoryDAO, schedulerJobDAO);
-	}
-
-	@Test
-	public void fetchSchedulerJobForUserAndExploratoryWhenNotebookNotExist() {
-		when(schedulerJobDAO.fetchSingleSchedulerJobByUserAndExploratory(anyString(), anyString(), anyString())).thenReturn(Optional.empty());
-		try {
-			schedulerJobService.fetchSchedulerJobForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME);
-		} catch (ResourceNotFoundException e) {
-			assertEquals("Scheduler job data not found for user test with exploratory explName", e.getMessage());
-		}
-		verify(schedulerJobDAO).fetchSingleSchedulerJobByUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME);
-		verifyNoMoreInteractions(schedulerJobDAO);
-	}
-
-	@Test
-	public void fetchEmptySchedulerJobForUserAndExploratory() {
-		when(schedulerJobDAO.fetchSingleSchedulerJobByUserAndExploratory(anyString(), anyString(), anyString()))
-				.thenReturn(Optional.empty());
-		try {
-			schedulerJobService.fetchSchedulerJobForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME);
-		} catch (ResourceNotFoundException e) {
-			assertEquals("Scheduler job data not found for user test with exploratory explName", e.getMessage());
-		}
-		verify(schedulerJobDAO).fetchSingleSchedulerJobByUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME);
-		verifyNoMoreInteractions(schedulerJobDAO);
-	}
-
-	@Test
-	public void fetchSchedulerJobForComputationalResource() {
-		when(schedulerJobDAO.fetchSingleSchedulerJobForCluster(anyString(), anyString(), anyString(), anyString()))
-				.thenReturn(Optional.of(schedulerJobDTO));
-
-		SchedulerJobDTO actualSchedulerJobDto = schedulerJobService
-				.fetchSchedulerJobForComputationalResource(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
-		assertNotNull(actualSchedulerJobDto);
-		assertEquals(schedulerJobDTO, actualSchedulerJobDto);
-
-		verify(schedulerJobDAO).fetchSingleSchedulerJobForCluster(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
-		verifyNoMoreInteractions(computationalDAO, schedulerJobDAO);
-	}
-
-	@Test
-	public void fetchEmptySchedulerJobForComputationalResource() {
-		when(schedulerJobDAO.fetchSingleSchedulerJobForCluster(anyString(), anyString(), anyString(), anyString()))
-				.thenReturn(Optional.empty());
-		try {
-			schedulerJobService.fetchSchedulerJobForComputationalResource(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
-		} catch (ResourceNotFoundException e) {
-			assertEquals("Scheduler job data not found for user test with exploratory explName with " +
-					"computational resource compName", e.getMessage());
-		}
-		verify(schedulerJobDAO).fetchSingleSchedulerJobForCluster(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
-		verifyNoMoreInteractions(computationalDAO, schedulerJobDAO);
-	}
-
-	@Test
-	public void updateSchedulerDataForUserAndExploratory() {
-        userInstance.withStatus("running");
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-        when(exploratoryDAO.updateSchedulerDataForUserAndExploratory(anyString(), anyString(), anyString(),
-                any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
-
-        schedulerJobService.updateExploratorySchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(exploratoryDAO).updateSchedulerDataForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
-        verify(computationalDAO).updateSchedulerSyncFlag(USER, PROJECT, EXPLORATORY_NAME, false);
-        verifyNoMoreInteractions(exploratoryDAO);
-        verifyZeroInteractions(computationalDAO);
-    }
-
-	@Test
-	public void updateSchedulerDataForUserAndExploratoryWhenMethodFetchExploratoryFieldsThrowsException() {
-		doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
-				.when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
-		try {
-            schedulerJobService.updateExploratorySchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
-        } catch (ResourceNotFoundException e) {
-			assertEquals("Exploratory for user with name not found", e.getMessage());
-		}
-		verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-		verifyNoMoreInteractions(exploratoryDAO);
-		verifyZeroInteractions(computationalDAO);
-	}
-
-	@Test
-	public void updateSchedulerDataForUserAndExploratoryWithInapproprietaryStatus() {
-		userInstance.withStatus("terminated");
-		when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-		try {
-            schedulerJobService.updateExploratorySchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
-        } catch (ResourceInappropriateStateException e) {
-			assertEquals("Can not create/update scheduler for user instance with status: terminated",
-					e.getMessage());
-		}
-		verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-		verifyNoMoreInteractions(exploratoryDAO);
-		verifyZeroInteractions(computationalDAO);
-	}
-
-	@Test
-	public void updateSchedulerDataForUserAndExploratoryWithEnrichingSchedulerJob() {
-        schedulerJobDTO.setBeginDate(null);
-        schedulerJobDTO.setTimeZoneOffset(null);
-        userInstance.withStatus("running");
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-        when(exploratoryDAO.updateSchedulerDataForUserAndExploratory(anyString(), anyString(), anyString(),
-                any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
-
-        assertNull(schedulerJobDTO.getBeginDate());
-        assertNull(schedulerJobDTO.getTimeZoneOffset());
-
-        schedulerJobService.updateExploratorySchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
-
-        assertEquals(LocalDate.now(), schedulerJobDTO.getBeginDate());
-        assertEquals(OffsetDateTime.now(ZoneId.systemDefault()).getOffset(), schedulerJobDTO.getTimeZoneOffset());
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(exploratoryDAO).updateSchedulerDataForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
-        verify(computationalDAO).updateSchedulerSyncFlag(USER, PROJECT, EXPLORATORY_NAME, false);
-        verifyNoMoreInteractions(exploratoryDAO);
-        verifyZeroInteractions(computationalDAO);
-    }
-
-	@Test
-	@SuppressWarnings("unchecked")
-	public void updateSchedulerDataForUserAndExploratoryWithSyncStartRequiredParam() {
-        userInstance.withStatus("running");
-        schedulerJobDTO.setSyncStartRequired(true);
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-        when(exploratoryDAO.updateSchedulerDataForUserAndExploratory(anyString(), anyString(), anyString(),
-                any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
-        when(computationalDAO.getComputationalResourcesWhereStatusIn(anyString(), anyString(),
-                any(List.class), anyString(), anyVararg())).thenReturn(singletonList(COMPUTATIONAL_NAME));
-        when(computationalDAO.updateSchedulerDataForComputationalResource(anyString(), anyString(), anyString(),
-                anyString(), any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
-
-        schedulerJobService.updateExploratorySchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(exploratoryDAO).updateSchedulerDataForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
-        verify(computationalDAO).getComputationalResourcesWhereStatusIn(USER, PROJECT,
-                singletonList(DataEngineType.SPARK_STANDALONE), EXPLORATORY_NAME, STARTING, RUNNING, STOPPING, STOPPED);
-        schedulerJobDTO.setEndTime(null);
-        schedulerJobDTO.setStopDaysRepeat(Collections.emptyList());
-        verify(computationalDAO).updateSchedulerDataForComputationalResource(USER, PROJECT,
-                EXPLORATORY_NAME, COMPUTATIONAL_NAME, schedulerJobDTO);
-        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
-	}
-
-	@Test
-	@SuppressWarnings("unchecked")
-	public void updateSchedulerDataForUserAndExploratoryWithSyncStartRequiredParamButAbsenceClusters() {
-        userInstance.withStatus("running");
-        schedulerJobDTO.setSyncStartRequired(true);
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-        when(exploratoryDAO.updateSchedulerDataForUserAndExploratory(anyString(), anyString(), anyString(),
-                any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
-        when(computationalDAO.getComputationalResourcesWhereStatusIn(anyString(), anyString(),
-                any(List.class), anyString(), anyVararg())).thenReturn(Collections.emptyList());
-
-        schedulerJobService.updateExploratorySchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(exploratoryDAO).updateSchedulerDataForUserAndExploratory(USER, PROJECT, EXPLORATORY_NAME, schedulerJobDTO);
-        verify(computationalDAO).getComputationalResourcesWhereStatusIn(USER, PROJECT,
-                singletonList(DataEngineType.SPARK_STANDALONE), EXPLORATORY_NAME, STARTING, RUNNING, STOPPING, STOPPED);
-        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
-    }
-
-	@Test
-	public void updateSchedulerDataForComputationalResource() {
-        userInstance.withStatus("running");
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-        when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString()))
-                .thenReturn(userInstance.getResources().get(0));
-        when(computationalDAO.updateSchedulerDataForComputationalResource(anyString(), anyString(), anyString(),
-                anyString(), any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
-
-        schedulerJobService.updateComputationalSchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME,
-                COMPUTATIONAL_NAME, schedulerJobDTO);
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
-        verify(computationalDAO).updateSchedulerDataForComputationalResource(USER, PROJECT,
-                EXPLORATORY_NAME, COMPUTATIONAL_NAME, schedulerJobDTO);
-        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
-    }
-
-	@Test
-	public void updateSchedulerDataForComputationalResourceWhenSchedulerIsNull() {
-		userInstance.withStatus("running");
-		when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-		when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString()))
-                .thenReturn(userInstance.getResources().get(0));
-        when(computationalDAO.updateSchedulerDataForComputationalResource(anyString(), anyString(), anyString(),
-                anyString(), any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
-
-        final SchedulerJobDTO schedulerJobDTO = getSchedulerJobDTO(LocalDate.now(), LocalDate.now().plusDays(1),
-                Arrays.asList(DayOfWeek.values()), Arrays.asList(DayOfWeek.values()), false,
-                LocalDateTime.of(LocalDate.now(), LocalTime.now().truncatedTo(ChronoUnit.MINUTES)),
-                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-        schedulerJobDTO.setStartDaysRepeat(null);
-        schedulerJobDTO.setStopDaysRepeat(null);
-        schedulerJobService.updateComputationalSchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME,
-                COMPUTATIONAL_NAME, schedulerJobDTO);
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
-        verify(computationalDAO).updateSchedulerDataForComputationalResource(eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME),
-                eq(COMPUTATIONAL_NAME), refEq(schedulerJobDTO));
-        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
-    }
-
-	@Test
-	public void updateSchedulerDataForComputationalResourceWhenMethodFetchComputationalFieldsThrowsException() {
-		userInstance.withStatus("running");
-		when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-		doThrow(new ResourceNotFoundException("Computational resource for user with name not found"))
-				.when(computationalDAO).fetchComputationalFields(anyString(), anyString(), anyString(), anyString());
-		try {
-            schedulerJobService.updateComputationalSchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME, schedulerJobDTO);
-        } catch (ResourceNotFoundException e) {
-			assertEquals("Computational resource for user with name not found", e.getMessage());
-		}
-
-		verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-		verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
-		verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
-	}
-
-	@Test
-	public void updateSchedulerDataForComputationalResourceWithInapproprietaryClusterStatus() {
-		userInstance.setStatus("running");
-		userInstance.getResources().get(0).setStatus("terminated");
-		when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-		when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString()))
-				.thenReturn(userInstance.getResources().get(0));
-		try {
-            schedulerJobService.updateComputationalSchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME, schedulerJobDTO);
-        } catch (ResourceInappropriateStateException e) {
-			assertEquals("Can not create/update scheduler for user instance with status: terminated",
-					e.getMessage());
-		}
-		verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-		verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
-		verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
-	}
-
-	@Test
-	public void updateSchedulerDataForComputationalResourceWithEnrichingSchedulerJob() {
-		schedulerJobDTO.setBeginDate(null);
-		schedulerJobDTO.setTimeZoneOffset(null);
-        userInstance.withStatus("running");
-        when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
-        when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString()))
-                .thenReturn(userInstance.getResources().get(0));
-        when(computationalDAO.updateSchedulerDataForComputationalResource(anyString(), anyString(), anyString(),
-                anyString(), any(SchedulerJobDTO.class))).thenReturn(mock(UpdateResult.class));
-
-        assertNull(schedulerJobDTO.getBeginDate());
-        assertNull(schedulerJobDTO.getTimeZoneOffset());
-
-        schedulerJobService.updateComputationalSchedulerData(getUserInfo(), PROJECT, EXPLORATORY_NAME,
-                COMPUTATIONAL_NAME, schedulerJobDTO);
-
-        assertEquals(LocalDate.now(), schedulerJobDTO.getBeginDate());
-        assertEquals(OffsetDateTime.now(ZoneId.systemDefault()).getOffset(), schedulerJobDTO.getTimeZoneOffset());
-
-        verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMPUTATIONAL_NAME);
-        verify(computationalDAO).updateSchedulerDataForComputationalResource(USER, PROJECT,
-                EXPLORATORY_NAME, COMPUTATIONAL_NAME, schedulerJobDTO);
-        verifyNoMoreInteractions(exploratoryDAO, computationalDAO);
-	}
-
-	@Test
-	public void testStartComputationalByScheduler() {
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).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());
-
-		schedulerJobService.startComputationalByScheduler();
-
-		verify(securityService).getServiceAccountInfo(USER);
-		verify(schedulerJobDAO)
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, STOPPED);
-		verify(computationalService).startSparkCluster(refEq(getUserInfo()), eq(EXPLORATORY_NAME),
-				eq(COMPUTATIONAL_NAME), eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-	}
-
-	@Test
-	public void testStartComputationalBySchedulerWhenSchedulerIsNotConfigured() {
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(Collections.emptyList());
-
-		schedulerJobService.startComputationalByScheduler();
-
-		verify(schedulerJobDAO).getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE,
-				STOPPED);
-		verifyNoMoreInteractions(schedulerJobDAO);
-		verifyZeroInteractions(securityService, computationalService);
-	}
-
-	@Test
-	public void testStartComputationalBySchedulerWhenSchedulerFinishDateBeforeNow() {
-		final LocalDate beginDate = LocalDate.now().plusDays(1);
-		final LocalDate endDate = LocalDate.now();
-		final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(beginDate, endDate, startDays, stopDays,
-				terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.startComputationalByScheduler();
-
-		verify(schedulerJobDAO)
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, STOPPED);
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-	}
-
-	@Test
-	public void testStartComputationalBySchedulerWhenSchedulerStartDateAfterNow() {
-		final LocalDate beginDate = LocalDate.now().plusDays(1);
-		final LocalDate finishDate = LocalDate.now();
-		final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(
-				beginDate, finishDate, startDays, stopDays, terminateDateTime, false, USER,
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.startComputationalByScheduler();
-
-		verify(schedulerJobDAO)
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, STOPPED);
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-	}
-
-	@Test
-	public void testStartComputationalBySchedulerWhenStartDayIsNotCurrentDay() {
-		final List<DayOfWeek> stopDays = Arrays.stream(DayOfWeek.values()).collect(Collectors.toList());
-		final List<DayOfWeek> startDays = Arrays.stream(DayOfWeek.values()).collect(Collectors.toList());
-		startDays.remove(LocalDate.now().getDayOfWeek());
-		final LocalDate beginDate = LocalDate.now();
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(
-				beginDate, LocalDate.now().minusDays(1), startDays, stopDays,
-				LocalDateTime.of(LocalDate.now(),
-						LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-		);
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.startComputationalByScheduler();
-
-		verify(schedulerJobDAO)
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, STOPPED);
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-	}
-
-
-	@Test
-	public void testStopComputationalByScheduler() {
-        UserInfo userInfo = getUserInfo();
-        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-                any(DataEngineType.class), anyVararg())).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(userInfo);
-
-        schedulerJobService.stopComputationalByScheduler();
-
-        verify(securityService).getServiceAccountInfo(USER);
-		verify(schedulerJobDAO)
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING);
-		verify(computationalService).stopSparkCluster(refEq(userInfo), eq(userInfo.getName()), eq(PROJECT),
-				eq(EXPLORATORY_NAME), eq(COMPUTATIONAL_NAME), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-    }
-
-	@Test
-	public void testStopComputationalBySchedulerWhenSchedulerIsNotConfigured() {
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(Collections.emptyList());
-
-		schedulerJobService.stopComputationalByScheduler();
-
-		verify(schedulerJobDAO)
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING);
-		verifyNoMoreInteractions(schedulerJobDAO);
-		verifyZeroInteractions(securityService, computationalService);
-	}
-
-	@Test
-	public void testStopComputationalBySchedulerWhenSchedulerFinishDateBeforeNow() {
-		final LocalDate beginDate = LocalDate.now().plusDays(1);
-		final LocalDate endDate = LocalDate.now();
-		final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(beginDate, endDate, startDays, stopDays,
-				terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.stopComputationalByScheduler();
-
-		verify(schedulerJobDAO)
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING);
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-	}
-
-	@Test
-	public void testStopComputationalBySchedulerWhenSchedulerStartDateAfterNow() {
-		final LocalDate beginDate = LocalDate.now().plusDays(1);
-		final LocalDate finishDate = LocalDate.now();
-		final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(
-				beginDate, finishDate, startDays, stopDays, terminateDateTime, false, USER,
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.stopComputationalByScheduler();
-
-		verify(schedulerJobDAO)
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING);
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-	}
-
-	@Test
-	public void testStopComputationalBySchedulerWhenStopDayIsNotCurrentDay() {
-		final List<DayOfWeek> stopDays = Arrays.stream(DayOfWeek.values()).collect(Collectors.toList());
-		stopDays.remove(LocalDate.now().getDayOfWeek());
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(
-				LocalDate.now(), LocalDate.now().minusDays(1), Arrays.asList(DayOfWeek.values()), stopDays,
-				LocalDateTime.of(LocalDate.now(),
-						LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-		);
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.stopComputationalByScheduler();
-
-		verify(schedulerJobDAO)
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, RUNNING);
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-	}
-
-
-	@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(userInfo);
-
-        schedulerJobService.stopExploratoryByScheduler();
-
-        verify(securityService).getServiceAccountInfo(USER);
-		verify(schedulerJobDAO).getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(eq(RUNNING),
-				any(Date.class));
-		verify(exploratoryService).stop(refEq(userInfo), eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService);
-    }
-
-	@Test
-	public void testStopExploratoryBySchedulerWhenSchedulerIsNotConfigured() {
-		when(schedulerJobDAO.getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(any(UserInstanceStatus.class), any(Date.class)))
-				.thenReturn(Collections.emptyList());
-
-		schedulerJobService.stopExploratoryByScheduler();
-
-		verify(schedulerJobDAO).getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(eq(RUNNING),
-				any(Date.class));
-		verifyNoMoreInteractions(schedulerJobDAO);
-		verifyZeroInteractions(securityService, exploratoryService);
-	}
-
-	@Test
-	public void testStopExploratoryBySchedulerWhenSchedulerFinishDateBeforeNow() {
-		final LocalDate finishDate = LocalDate.now().minusDays(1);
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(LocalDate.now(), finishDate,
-				Arrays.asList(DayOfWeek.values()), stopDays, LocalDateTime.of(LocalDate.now(),
-						LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-		);
-		when(schedulerJobDAO.getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(any(UserInstanceStatus.class), any(Date.class))).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.stopExploratoryByScheduler();
-
-		verify(schedulerJobDAO).getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(eq(RUNNING),
-				any(Date.class));
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService);
-	}
-
-	@Test
-	public void testStopExploratoryBySchedulerWhenSchedulerStartDateAfterNow() {
-        final LocalDate now = LocalDate.now();
-        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-        final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
-        final LocalDate beginDate = now.plusDays(1);
-        final LocalDateTime terminateDateTime = LocalDateTime.of(now, LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-        final SchedulerJobData schedulerJobData = getSchedulerJobData(beginDate, now, startDays, stopDays,
-                terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-        );
-        when(schedulerJobDAO.getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(any(UserInstanceStatus.class), any(Date.class)))
-                .thenReturn(singletonList(schedulerJobData));
-        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-        schedulerJobService.stopExploratoryByScheduler();
-
-        verify(schedulerJobDAO).getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(eq(RUNNING),
-                any(Date.class));
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService);
-	}
-
-	@Test
-	public void testStopExploratoryBySchedulerWhenStopDayIsNotCurrentDay() {
-		final List<DayOfWeek> stopDays = Arrays.stream((DayOfWeek.values())).collect(Collectors.toList());
-		stopDays.remove(LocalDate.now().getDayOfWeek());
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(
-				LocalDate.now(), LocalDate.now().minusDays(1), Arrays.asList(DayOfWeek.values()), stopDays,
-				LocalDateTime.of(LocalDate.now(),
-						LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-		);
-		when(schedulerJobDAO.getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(any(UserInstanceStatus.class), any(Date.class))).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.stopExploratoryByScheduler();
-
-		verify(schedulerJobDAO).getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(eq(RUNNING),
-				any(Date.class));
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService);
-	}
-
-
-	@Test
-	public void testStartExploratoryByScheduler() {
-		final LocalDate finishDate = LocalDate.now().plusDays(1);
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class)))
-				.thenReturn(singletonList(getSchedulerJobData(LocalDate.now(), finishDate,
-                        Arrays.asList(DayOfWeek.values()), stopDays, LocalDateTime.of(LocalDate.now(),
-                                LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
-                        LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-                )));
-        when(securityService.getServiceAccountInfo(anyString())).thenReturn(getUserInfo());
-
-        schedulerJobService.startExploratoryByScheduler();
-
-        verify(securityService).getServiceAccountInfo(USER);
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
-		verifyNoMoreInteractions(schedulerJobDAO, exploratoryService);
-        verifyZeroInteractions(computationalService, computationalDAO);
-    }
-
-	@Test
-	public void testStartExploratoryBySchedulerWithSyncComputationalStart() {
-		final LocalDate finishDate = LocalDate.now().plusDays(1);
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class)))
-				.thenReturn(singletonList(getSchedulerJobData(LocalDate.now(), finishDate,
-						Arrays.asList(DayOfWeek.values()), stopDays, LocalDateTime.of(LocalDate.now(),
-								LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), true, USER,
-						LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-				)));
-		when(securityService.getServiceAccountInfo(anyString())).thenReturn(getUserInfo());
-        when(computationalDAO.findComputationalResourcesWithStatus(anyString(), anyString(),
-                anyString(), any(UserInstanceStatus.class))).thenReturn(singletonList(getComputationalResource(
-                DataEngineType.SPARK_STANDALONE, true)));
-
-        schedulerJobService.startExploratoryByScheduler();
-
-        verify(securityService, times(2)).getServiceAccountInfo(USER);
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
-		verify(computationalDAO).findComputationalResourcesWithStatus(USER, PROJECT, EXPLORATORY_NAME, STOPPED);
-		verify(computationalService).startSparkCluster(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(COMPUTATIONAL_NAME),
-				eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService, computationalService,
-				computationalDAO);
-    }
-
-	@Test
-	public void testStartExploratoryBySchedulerWithSyncComputationalStartDataEngine() {
-		final LocalDate finishDate = LocalDate.now().plusDays(1);
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class)))
-				.thenReturn(singletonList(getSchedulerJobData(LocalDate.now(), finishDate,
-						Arrays.asList(DayOfWeek.values()), stopDays, LocalDateTime.of(LocalDate.now(),
-								LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), true, USER,
-						LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-                )));
-        when(securityService.getServiceAccountInfo(anyString())).thenReturn(getUserInfo());
-        when(computationalDAO.findComputationalResourcesWithStatus(anyString(), anyString(),
-                anyString(), any(UserInstanceStatus.class))).thenReturn(singletonList(getComputationalResource(
-                DataEngineType.CLOUD_SERVICE, true)));
-
-        schedulerJobService.startExploratoryByScheduler();
-
-        verify(securityService).getServiceAccountInfo(USER);
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
-		verify(computationalDAO).findComputationalResourcesWithStatus(USER, PROJECT, EXPLORATORY_NAME, STOPPED);
-        verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService, computationalDAO);
-        verifyZeroInteractions(computationalService);
-    }
-
-	@Test
-	public void testStartExploratoryBySchedulerWithSyncComputationalStartOnExploratoryButNotOnComputational() {
-		final LocalDate finishDate = LocalDate.now().plusDays(1);
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class)))
-				.thenReturn(singletonList(getSchedulerJobData(LocalDate.now(), finishDate,
-						Arrays.asList(DayOfWeek.values()), stopDays, LocalDateTime.of(LocalDate.now(),
-								LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), true, USER,
-						LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-                )));
-        when(securityService.getServiceAccountInfo(anyString())).thenReturn(getUserInfo());
-        when(computationalDAO.findComputationalResourcesWithStatus(anyString(), anyString(),
-                anyString(), any(UserInstanceStatus.class))).thenReturn(singletonList(getComputationalResource(
-                DataEngineType.SPARK_STANDALONE, false)));
-
-        schedulerJobService.startExploratoryByScheduler();
-
-        verify(securityService).getServiceAccountInfo(USER);
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
-		verify(computationalDAO).findComputationalResourcesWithStatus(USER, PROJECT, EXPLORATORY_NAME, STOPPED);
-        verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService, computationalDAO);
-        verifyZeroInteractions(computationalService);
-    }
-
-	@Test
-	public void testStartExploratoryBySchedulerWhenSchedulerIsNotConfigured() {
-		when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class))).thenReturn(Collections.emptyList());
-
-		schedulerJobService.startExploratoryByScheduler();
-
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verifyNoMoreInteractions(schedulerJobDAO);
-		verifyZeroInteractions(securityService, exploratoryService, computationalService, computationalDAO);
-	}
-
-	@Test
-	public void testStartExploratoryBySchedulerWhenSchedulerFinishDateBeforeNow() {
-		final LocalDate finishDate = LocalDate.now().minusDays(1);
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(LocalDate.now(), finishDate,
-				Arrays.asList(DayOfWeek.values()), stopDays, LocalDateTime.of(LocalDate.now(),
-						LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-		);
-		when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class))).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.startExploratoryByScheduler();
-
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verifyZeroInteractions(securityService, exploratoryService, computationalService, computationalDAO);
-	}
-
-	@Test
-	public void testStartExploratoryBySchedulerWhenSchedulerStartDateAfterNow() {
-		final LocalDate finishDate = LocalDate.now();
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		final LocalDate beginDate = LocalDate.now().plusDays(1);
-		final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
-		final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(beginDate, finishDate, startDays, stopDays,
-				terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class))).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.startExploratoryByScheduler();
-
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verifyZeroInteractions(securityService, exploratoryService, computationalService, computationalDAO);
-	}
-
-	@Test
-	public void testStartExploratoryBySchedulerWhenStartDayIsNotCurrentDay() {
-		final List<DayOfWeek> stopDays = Arrays.stream((DayOfWeek.values())).collect(Collectors.toList());
-		final List<DayOfWeek> startDays = Arrays.stream(DayOfWeek.values()).collect(Collectors.toList());
-		startDays.remove(LocalDate.now().getDayOfWeek());
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(
-				LocalDate.now(), LocalDate.now().minusDays(1), startDays, stopDays, LocalDateTime.of(LocalDate.now(),
-						LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class))).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.startExploratoryByScheduler();
-
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verifyZeroInteractions(securityService, exploratoryService, computationalService, computationalDAO);
-	}
-
-
-	@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));
-        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(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-    }
-
-	@Test
-	public void testTerminateComputationalBySchedulerWhenSchedulerIsNotConfigured() {
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(Collections.emptyList());
-
-		schedulerJobService.terminateComputationalByScheduler();
-
-		verify(schedulerJobDAO).getComputationalSchedulerDataWithOneOfStatus(RUNNING, STOPPED, RUNNING);
-		verifyNoMoreInteractions(schedulerJobDAO);
-		verifyZeroInteractions(securityService, computationalService);
-	}
-
-	@Test
-	public void testTerminateComputationalBySchedulerWhenSchedulerFinishDateBeforeNow() {
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(
-				LocalDate.now(), LocalDate.now().minusDays(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(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.terminateComputationalByScheduler();
-
-		verify(schedulerJobDAO).getComputationalSchedulerDataWithOneOfStatus(RUNNING, STOPPED, RUNNING);
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-	}
-
-	@Test
-	public void testTerminateComputationalBySchedulerWhenSchedulerStartDateAfterNow() {
-		final LocalDate beginDate = LocalDate.now().plusDays(1);
-		final LocalDate finishDate = LocalDate.now();
-		final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(beginDate, finishDate, startDays, stopDays,
-				terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.terminateComputationalByScheduler();
-
-		verify(schedulerJobDAO).getComputationalSchedulerDataWithOneOfStatus(RUNNING, STOPPED, RUNNING);
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-	}
-
-	@Test
-	public void testTerminateComputationalBySchedulerWhenTerminateDateNotCurrent() {
-		final List<DayOfWeek> stopDays = Arrays.stream(DayOfWeek.values()).collect(Collectors.toList());
-		stopDays.remove(LocalDate.now().getDayOfWeek());
-		final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES)).plusDays(1);
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(
-				LocalDate.now(), LocalDate.now().minusDays(1), Arrays.asList(DayOfWeek.values()), stopDays,
-				terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-		);
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.terminateComputationalByScheduler();
-
-		verify(schedulerJobDAO)
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, STOPPED, RUNNING);
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-	}
-
-	@Test
-	public void testTerminateExploratoryByScheduler() {
-		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.getExploratorySchedulerDataWithOneOfStatus(anyVararg())).thenReturn(singletonList(schedulerJobData));
-        when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-        schedulerJobService.terminateExploratoryByScheduler();
-
-        verify(securityService).getUserInfoOffline(USER);
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED);
-		verify(exploratoryService).terminate(refEq(getUserInfo()), eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME), eq(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME)));
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService, exploratoryService);
-    }
-
-	@Test
-	public void testTerminateExploratoryBySchedulerWhenSchedulerIsNotConfigured() {
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(Collections.emptyList());
-
-		schedulerJobService.terminateExploratoryByScheduler();
-
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED);
-		verifyNoMoreInteractions(schedulerJobDAO);
-		verifyZeroInteractions(securityService, exploratoryService, computationalService);
-	}
-
-	@Test
-	public void testTerminateExploratoryBySchedulerWhenSchedulerFinishDateBeforeNow() {
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(
-				LocalDate.now(), LocalDate.now().minusDays(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(schedulerJobDAO.getExploratorySchedulerDataWithOneOfStatus(anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.terminateExploratoryByScheduler();
-
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED);
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService, computationalService);
-	}
-
-	@Test
-	public void testTerminateExploratoryBySchedulerWhenSchedulerStartDateAfterNow() {
-		final LocalDate beginDate = LocalDate.now().plusDays(1);
-		final LocalDate finishDate = LocalDate.now();
-		final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(
-				beginDate, finishDate, startDays, stopDays, terminateDateTime, false, USER,
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		when(schedulerJobDAO.getExploratorySchedulerDataWithOneOfStatus(anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.terminateExploratoryByScheduler();
-
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED);
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService, computationalService);
-	}
-
-	@Test
-	public void testTerminateExploratoryBySchedulerWhenTerminateDateNotCurrent() {
-		final List<DayOfWeek> stopDays = Arrays.stream(DayOfWeek.values()).collect(Collectors.toList());
-		stopDays.remove(LocalDate.now().getDayOfWeek());
-		final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES)).plusDays(1);
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(
-				LocalDate.now(), LocalDate.now().minusDays(1), Arrays.asList(DayOfWeek.values()), stopDays,
-				terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-		);
-		when(schedulerJobDAO.getExploratorySchedulerDataWithOneOfStatus(anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.terminateExploratoryByScheduler();
-
-		verify(schedulerJobDAO).getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED);
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService, exploratoryService);
-	}
-
-	@Test
-	public void testGetActiveSchedulers() {
-		final int minutesOffset = 123;
-		final LocalDate now = LocalDate.now();
-		final DayOfWeek[] weekDays = DayOfWeek.values();
-		final LocalTime currentTime = LocalTime.now();
-		final LocalTime offsetTime = LocalTime.now().plusMinutes(1);
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(now,
-				now.plusDays(1), Arrays.asList(weekDays), Arrays.asList(weekDays),
-				LocalDateTime.of(now, currentTime.plusMinutes(minutesOffset).truncatedTo(ChronoUnit.MINUTES)), false,
-				USER, offsetTime.truncatedTo(ChronoUnit.MINUTES));
-
-		final SchedulerJobData secondScheduler = getSchedulerJobData(now,
-				now.plusDays(1), Arrays.asList(weekDays), Arrays.asList(weekDays),
-				LocalDateTime.of(now, currentTime.plusMinutes(minutesOffset).truncatedTo(ChronoUnit.MINUTES)),
-				false, "user123", offsetTime.truncatedTo(ChronoUnit.MINUTES));
-
-		when(schedulerJobDAO.getExploratorySchedulerDataWithStatus(any(UserInstanceStatus.class))).thenReturn(Arrays.asList(schedulerJobData, secondScheduler));
-		when(securityService.getUserInfoOffline(anyString())).thenReturn(getUserInfo());
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				any(DataEngineType.class), anyVararg())).thenReturn(singletonList(schedulerJobData));
-
-		final List<SchedulerJobData> activeSchedulers = schedulerJobService.getActiveSchedulers(USER, minutesOffset);
-
-		assertEquals(2, activeSchedulers.size());
-	}
-
-	private SchedulerJobData getSchedulerJobData(LocalDate beginDate, LocalDate schedulerFinishDate,
-												 List<DayOfWeek> startDays, List<DayOfWeek> stopDays,
-												 LocalDateTime terminateDateTime, boolean syncStartRequired,
-												 String user, LocalTime endTime) {
-		return new SchedulerJobData(user, EXPLORATORY_NAME, COMPUTATIONAL_NAME, PROJECT, getSchedulerJobDTO(beginDate,
-				schedulerFinishDate, startDays, stopDays, syncStartRequired, terminateDateTime, endTime));
-	}
-
-	private UserInfo getUserInfo() {
-		return new UserInfo(USER, "token");
-	}
-
-	private SchedulerJobDTO getSchedulerJobDTO(LocalDate beginDate, LocalDate finishDate, List<DayOfWeek> startDays,
-											   List<DayOfWeek> stopDays, boolean syncStartRequired,
-											   LocalDateTime terminateDateTime, LocalTime endTime) {
-		SchedulerJobDTO schedulerJobDTO = new SchedulerJobDTO();
-		schedulerJobDTO.setTimeZoneOffset(OffsetDateTime.now(ZoneId.systemDefault()).getOffset());
-		schedulerJobDTO.setBeginDate(beginDate);
-		schedulerJobDTO.setFinishDate(finishDate);
-		schedulerJobDTO.setStartTime(LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		schedulerJobDTO.setEndTime(endTime);
-		schedulerJobDTO.setTerminateDateTime(terminateDateTime);
-		schedulerJobDTO.setStartDaysRepeat(startDays);
-		schedulerJobDTO.setStopDaysRepeat(stopDays);
-		schedulerJobDTO.setSyncStartRequired(syncStartRequired);
-		return schedulerJobDTO;
-	}
-
-	private UserInstanceDTO getUserInstanceDTO() {
-		UserComputationalResource computationalResource = new UserComputationalResource();
-		computationalResource.setStatus("running");
-		return new UserInstanceDTO()
-				.withUser(USER)
-				.withExploratoryName(EXPLORATORY_NAME)
-				.withResources(singletonList(computationalResource))
-				.withProject(PROJECT);
-	}
-
-	private AwsComputationalResource getComputationalResource(DataEngineType dataEngineType,
-															  boolean syncStartRequired) {
-		final SchedulerJobDTO schedulerJobData = new SchedulerJobDTO();
-		schedulerJobData.setSyncStartRequired(syncStartRequired);
-		return AwsComputationalResource.builder()
-				.computationalName("compName")
-				.imageName(DataEngineType.getDockerImageName(dataEngineType))
-				.schedulerJobData(schedulerJobData)
-				.build();
-	}
-}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/SystemInfoServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/SystemInfoServiceImplTest.java
deleted file mode 100644
index ca3835c..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/SystemInfoServiceImplTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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.resources.dto.SystemInfoDto;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import oshi.SystemInfo;
-import oshi.hardware.CentralProcessor;
-import oshi.hardware.GlobalMemory;
-import oshi.hardware.HWDiskStore;
-import oshi.hardware.HardwareAbstractionLayer;
-import oshi.software.os.FileSystem;
-import oshi.software.os.OSFileStore;
-import oshi.software.os.OperatingSystem;
-import oshi.software.os.OperatingSystemVersion;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class SystemInfoServiceImplTest {
-
-	private static final String OS_VERSION = "OS version";
-	private static final String OS_FAMILY = "OS FAMILY";
-	private static final String BUILD_NUMBER = "BUILD 1.0";
-	private static final String PROCESSOR_MODEL = "Proc model";
-	private static final long AVAILABLE_MEMORY = 100L;
-	private static final long USABLE_SPACE = 100L;
-	private static final long TOTAL_SPACE = 1000L;
-	@Mock
-	private SystemInfo si;
-
-	@InjectMocks
-	private SystemInfoServiceImpl systemInfoService;
-
-	@Test
-	public void getSystemInfo() {
-		final OperatingSystem os = mock(OperatingSystem.class);
-		final HardwareAbstractionLayer hardwareAbstractionLayer = mock(HardwareAbstractionLayer.class);
-		final OperatingSystemVersion operatingSystemVersion = mock(OperatingSystemVersion.class);
-		final CentralProcessor centralProcessor = mock(CentralProcessor.class);
-		final GlobalMemory globalMemory = mock(GlobalMemory.class);
-		final FileSystem fileSystem = mock(FileSystem.class);
-		final OSFileStore osFileStore = new OSFileStore();
-		osFileStore.setUsableSpace(USABLE_SPACE);
-		osFileStore.setTotalSpace(TOTAL_SPACE);
-		when(fileSystem.getFileStores()).thenReturn(new OSFileStore[]{osFileStore});
-
-		when(operatingSystemVersion.getVersion()).thenReturn(OS_VERSION);
-		when(operatingSystemVersion.getBuildNumber()).thenReturn(BUILD_NUMBER);
-		when(hardwareAbstractionLayer.getDiskStores()).thenReturn(new HWDiskStore[]{});
-		when(os.getFamily()).thenReturn(OS_FAMILY);
-		when(os.getVersion()).thenReturn(operatingSystemVersion);
-		when(si.getOperatingSystem()).thenReturn(os);
-		when(os.getFileSystem()).thenReturn(fileSystem);
-		when(globalMemory.getAvailable()).thenReturn(AVAILABLE_MEMORY);
-		when(hardwareAbstractionLayer.getMemory()).thenReturn(globalMemory);
-		when(centralProcessor.getModel()).thenReturn(PROCESSOR_MODEL);
-		when(hardwareAbstractionLayer.getProcessor()).thenReturn(centralProcessor);
-		when(si.getHardware()).thenReturn(hardwareAbstractionLayer);
-
-		SystemInfoDto systemInfo = systemInfoService.getSystemInfo();
-
-		assertEquals(BUILD_NUMBER, systemInfo.getOsInfo().getBuildNumber());
-		assertEquals(OS_VERSION, systemInfo.getOsInfo().getVersion());
-		assertEquals(OS_FAMILY, systemInfo.getOsInfo().getFamily());
-		assertEquals(PROCESSOR_MODEL, systemInfo.getProcessorInfo().getModel());
-		assertEquals(AVAILABLE_MEMORY, systemInfo.getMemoryInfo().getAvailableMemory());
-		assertEquals(1, systemInfo.getDisksInfo().size());
-
-		verify(si).getOperatingSystem();
-		verify(si).getHardware();
-		verifyNoMoreInteractions(si, fileSystem);
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/UserGroupServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/UserGroupServiceImplTest.java
deleted file mode 100644
index 3b3e901..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/UserGroupServiceImplTest.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * 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.ProjectDAO;
-import com.epam.dlab.backendapi.dao.UserGroupDAO;
-import com.epam.dlab.backendapi.dao.UserRoleDAO;
-import com.epam.dlab.backendapi.domain.ProjectDTO;
-import com.epam.dlab.backendapi.resources.TestBase;
-import com.epam.dlab.backendapi.resources.dto.UserGroupDto;
-import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.exceptions.DlabException;
-import com.epam.dlab.exceptions.ResourceNotFoundException;
-import io.dropwizard.auth.AuthenticationException;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.anySet;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class UserGroupServiceImplTest extends TestBase {
-
-	private static final String ROLE_ID = "Role id";
-	private static final String USER = "test";
-	private static final String GROUP = "admin";
-	@Mock
-	private UserRoleDAO userRoleDao;
-	@Mock
-	private UserGroupDAO userGroupDao;
-	@Mock
-	private ProjectDAO projectDAO;
-	@InjectMocks
-	private UserGroupServiceImpl userGroupService;
-
-	@Rule
-	public ExpectedException expectedException = ExpectedException.none();
-
-	@Before
-	public void setup() throws AuthenticationException {
-		authSetup();
-	}
-
-    @Test
-    public void createGroup() {
-        when(userRoleDao.addGroupToRole(anySet(), anySet())).thenReturn(true);
-
-        userGroupService.createGroup(getUserInfo(), GROUP, Collections.singleton(ROLE_ID), Collections.singleton(USER));
-
-        verify(userRoleDao).addGroupToRole(Collections.singleton(GROUP), Collections.singleton(ROLE_ID));
-        verify(userGroupDao).addUsers(GROUP, Collections.singleton(USER));
-    }
-
-	@Test
-	public void createGroupWithNoUsers() {
-		when(userRoleDao.addGroupToRole(anySet(), anySet())).thenReturn(true);
-
-		userGroupService.createGroup(getUserInfo(), GROUP, Collections.singleton(ROLE_ID), Collections.emptySet());
-
-		verify(userRoleDao).addGroupToRole(Collections.singleton(GROUP), Collections.singleton(ROLE_ID));
-		verify(userGroupDao).addUsers(anyString(), anySet());
-	}
-
-	@Test
-	public void createGroupWhenRoleNotFound() {
-		when(userRoleDao.addGroupToRole(anySet(), anySet())).thenReturn(false);
-
-		expectedException.expect(ResourceNotFoundException.class);
-		userGroupService.createGroup(getUserInfo(), GROUP, Collections.singleton(ROLE_ID), Collections.singleton(USER));
-	}
-
-	@Test
-	public void removeGroup() {
-
-		when(userRoleDao.removeGroup(anyString())).thenReturn(true);
-		final ProjectDTO projectDTO = new ProjectDTO(
-				"name", Collections.emptySet(), "", "", null, Collections.emptyList(), true);
-		when(projectDAO.getProjectsWithEndpointStatusNotIn(UserInstanceStatus.TERMINATED,
-				UserInstanceStatus.TERMINATING)).thenReturn(Collections.singletonList(projectDTO));
-		doNothing().when(userGroupDao).removeGroup(anyString());
-
-		userGroupService.removeGroup(getUserInfo(), GROUP);
-
-		verify(userRoleDao).removeGroup(GROUP);
-		verify(userGroupDao).removeGroup(GROUP);
-		verifyNoMoreInteractions(userGroupDao, userRoleDao);
-	}
-
-	@Test
-	public void removeGroupWhenItIsUsedInProject() {
-
-		when(userRoleDao.removeGroup(anyString())).thenReturn(true);
-		when(projectDAO.getProjectsWithEndpointStatusNotIn(UserInstanceStatus.TERMINATED,
-				UserInstanceStatus.TERMINATING)).thenReturn(Collections.singletonList( new ProjectDTO(
-				"name", Collections.singleton(GROUP), "", "", null, Collections.emptyList(), true)));
-		doNothing().when(userGroupDao).removeGroup(anyString());
-
-		try {
-			userGroupService.removeGroup(getUserInfo(), GROUP);
-		} catch (Exception e){
-			assertEquals("Group can not be removed because it is used in some project", e.getMessage());
-		}
-
-		verify(userRoleDao, never()).removeGroup(GROUP);
-		verify(userGroupDao, never()).removeGroup(GROUP);
-		verifyNoMoreInteractions(userGroupDao, userRoleDao);
-	}
-
-	@Test
-	public void removeGroupWhenGroupNotExist() {
-
-		final ProjectDTO projectDTO = new ProjectDTO(
-				"name", Collections.emptySet(), "", "", null, Collections.emptyList(), true);
-		when(projectDAO.getProjectsWithEndpointStatusNotIn(UserInstanceStatus.TERMINATED,
-				UserInstanceStatus.TERMINATING)).thenReturn(Collections.singletonList(projectDTO));
-		when(userRoleDao.removeGroup(anyString())).thenReturn(false);
-		doNothing().when(userGroupDao).removeGroup(anyString());
-
-		userGroupService.removeGroup(getUserInfo(), GROUP);
-
-		verify(userRoleDao).removeGroup(GROUP);
-		verify(userGroupDao).removeGroup(GROUP);
-		verifyNoMoreInteractions(userGroupDao, userRoleDao);
-	}
-
-	@Test
-	public void removeGroupWithException() {
-		final ProjectDTO projectDTO = new ProjectDTO(
-				"name", Collections.emptySet(), "", "", null, Collections.emptyList(), true);
-		when(projectDAO.getProjectsWithEndpointStatusNotIn(UserInstanceStatus.TERMINATED,
-				UserInstanceStatus.TERMINATING)).thenReturn(Collections.singletonList(projectDTO));
-		when(userRoleDao.removeGroup(anyString())).thenThrow(new DlabException("Exception"));
-
-		expectedException.expectMessage("Exception");
-		expectedException.expect(DlabException.class);
-
-		userGroupService.removeGroup(getUserInfo(), GROUP);
-	}
-
-    private UserGroupDto getUserGroup() {
-        return new UserGroupDto(GROUP, Collections.emptyList(), Collections.emptySet());
-    }
-
-    private List<ProjectDTO> getProjects() {
-        return Collections.singletonList(ProjectDTO.builder()
-                .groups(new HashSet<>(Collections.singletonList(GROUP)))
-                .build());
-    }
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/util/CSVFormatterTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/util/CSVFormatterTest.java
deleted file mode 100644
index cdbe93f..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/util/CSVFormatterTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.util;
-
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-
-public class CSVFormatterTest {
-
-	@Test
-	public void formatLine() {
-		List<String> values = Arrays.asList("aaa", "bbb", "ccc", "aa", "bb", "cc", "a", "b", "c");
-		String expected = "aaa,bbb,ccc,aa,bb,cc,a,b,c\n";
-		String actual = CSVFormatter.formatLine(values, ',');
-		assertEquals(expected, actual);
-	}
-
-	@Test
-	public void formatLineWithCustomQuote() {
-		List<String> values = Arrays.asList("aaa", "bbb", "ccc", "aa", "bb", "cc", "a", "b", "c");
-		String expected = "\"aaa\",\"bbb\",\"ccc\",\"aa\",\"bb\",\"cc\",\"a\",\"b\",\"c\"\n";
-		String actual = CSVFormatter.formatLine(values, ',', '"');
-		assertEquals(expected, actual);
-	}
-}
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/util/DateRemoverUtilTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/util/DateRemoverUtilTest.java
deleted file mode 100644
index 5677e77..0000000
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/util/DateRemoverUtilTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.util;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class DateRemoverUtilTest {
-
-	@Test
-	public void removeDateFormErrorMessageWithErrorDateFormat() {
-		String errorMessage = "All dates with format '[Error-2018-04-12 15:30:35]:' are erroneous";
-		String expected = "All dates with format 'yyyy-MM-dd' are erroneous";
-		String actual = DateRemoverUtil.removeDateFormErrorMessage(errorMessage, "\\[Error-\\d{4}-\\d{2}-" +
-				"\\d{2} \\d{2}:\\d{2}:\\d{2}\\]:", "yyyy-MM-dd");
-		assertEquals(expected, actual);
-	}
-
-	@Test
-	public void removeDateFormErrorMessage1() {
-		String errorMessage = "All dates with format '[Error-2018-04-12 15:30:35]:' are erroneous";
-		String expected = "All dates with format '[Error]:' are erroneous";
-		String actual = DateRemoverUtil.removeDateFormErrorMessage(errorMessage);
-		assertEquals(expected, actual);
-	}
-}
\ No newline at end of file